TeMappedMemory.cpp

Go to the documentation of this file.
00001 /************************************************************************************
00002 TerraLib - a library for developing GIS applications.
00003 Copyright � 2001-2007 INPE and Tecgraf/PUC-Rio.
00004 
00005 This code is part of the TerraLib library.
00006 This library is free software; you can redistribute it and/or
00007 modify it under the terms of the GNU Lesser General Public
00008 License as published by the Free Software Foundation; either
00009 version 2.1 of the License, or (at your option) any later version.
00010 
00011 You should have received a copy of the GNU Lesser General Public
00012 License along with this library.
00013 
00014 The authors reassure the license terms regarding the warranties.
00015 They specifically disclaim any warranties, including, but not limited to,
00016 the implied warranties of merchantability and fitness for a particular purpose.
00017 The library provided hereunder is on an "as is" basis, and the authors have no
00018 obligation to provide maintenance, support, updates, enhancements, or modifications.
00019 In no event shall INPE and Tecgraf / PUC-Rio be held liable to any party for direct,
00020 indirect, special, incidental, or consequential damages arising out of the use
00021 of this library and its documentation.
00022 *************************************************************************************/
00023 
00024 #include "TeMappedMemory.h"
00025 #include "TeException.h"
00026 #include "TeErrorLog.h"
00027 #include "TeUtils.h"
00028 #include "TeAgnostic.h"
00029 #include "TeDefines.h"
00030 #include "TeTempFilesRemover.h"
00031 
00032 #if TePLATFORM == TePLATFORMCODE_MSWINDOWS
00033   #include <io.h>
00034   #include <fcntl.h>
00035   #include <sys/stat.h>  
00036 #elif TePLATFORM == TePLATFORMCODE_LINUX || TePLATFORM == TePLATFORMCODE_AIX || TePLATFORM == TePLATFORMCODE_APPLE
00037   #include <sys/types.h>
00038   #include <sys/stat.h>
00039   #include <fcntl.h>
00040   #include <unistd.h>
00041 #else
00042   #error "Unsupported platform"
00043 #endif
00044 
00045 
00046 void TeMappedMemory::init()
00047 {
00048   #if TePLATFORM == TePLATFORMCODE_MSWINDOWS
00049     m_hFile_ = 0;
00050     m_hMapping_ = 0;
00051     m_lpszFile_ = 0;
00052   #elif TePLATFORM == TePLATFORMCODE_LINUX || TePLATFORM == TePLATFORMCODE_AIX || TePLATFORM == TePLATFORMCODE_APPLE
00053     m_hFile_ = 0;
00054     m_lpszFile_ = 0;
00055   #else
00056     #error "Unsupported platform"
00057   #endif
00058   
00059   mapping_is_active_ = false;
00060   curr_size_ = 0;
00061   must_delete_file_ = false;
00062 };
00063 
00064 
00065 TeMappedMemory::TeMappedMemory()
00066 {
00067   init();
00068 }
00069 
00070 
00071 TeMappedMemory::~TeMappedMemory()
00072 {
00073   reset();
00074 }
00075 
00076 
00077 void TeMappedMemory::reset()
00078 {
00079   TEAGN_TRUE_OR_THROW( toggle( false ), "Error disabling mapped memory" );
00080   
00081   if( must_delete_file_ ) {
00082     TeTempFilesRemover::instance().removeFile(disk_file_name_);
00083   }
00084   
00085   disk_file_name_.clear();
00086   
00087   init();
00088 }
00089 
00090 
00091 bool TeMappedMemory::reset( unsigned long int size, bool enabled )
00092 {
00093   reset();
00094   
00095   std::string disk_file_name;
00096       
00097   TEAGN_TRUE_OR_RETURN( TeGetTempFileName( disk_file_name ),
00098     "Unable to get temporary file name" );
00099     
00100   return( reset( disk_file_name, size, false, enabled ) );
00101 }
00102 
00103 
00104 bool TeMappedMemory::reset( const std::string& filename, 
00105   unsigned long int size, bool keep_disk_file, bool enabled )
00106 {
00107   reset();
00108 
00109   if( filename.empty() || ( size == 0 ) ) {
00110     TeErrorLog::instance().insert( UNKNOWN_ERROR_TYPE,
00111       "Invalid mapped file name or invalid file size" ); 
00112             
00113     return false;
00114   } else {
00115     TEAGN_TRUE_OR_RETURN( createNewDiskFile( filename, size ),
00116       "Unable to create memory mapped disk file" );
00117       
00118     disk_file_name_ = filename;
00119     must_delete_file_ = ( ! keep_disk_file );
00120     
00121     if( must_delete_file_ )
00122     {
00123       TeTempFilesRemover::instance().addFile( filename );
00124     }
00125     
00126     if( toggle( enabled ) ) {
00127       return true;
00128     } else {
00129       reset();
00130       return false;
00131     }
00132   }
00133 }
00134 
00135 
00136 bool TeMappedMemory::reset( const std::string& filename, bool enabled )
00137 {
00138   reset();
00139   
00140   disk_file_name_ = filename;
00141   
00142   if( toggle( enabled ) ) {
00143     return true;
00144   } else {
00145     reset();
00146     return false;
00147   }  
00148 }
00149 
00150 
00151 bool TeMappedMemory::toggle( bool enabled )
00152 {
00153   if( enabled  ) {
00154     if( mapping_is_active_ ) {
00155       return true;    
00156     } else {
00157       curr_size_ = 0;
00158       
00159       /* Activating mapping */    
00160       
00161       if( ! TeCheckFileExistence( disk_file_name_.c_str() ) ) {
00162         return false;
00163       }
00164       
00165       unsigned long int filesize = TeGetFileSize( disk_file_name_ );
00166   
00167       if( filesize > 0 ) {
00168         #if TePLATFORM == TePLATFORMCODE_MSWINDOWS
00169       
00170           HANDLE m_hFile = CreateFileA(
00171             disk_file_name_.c_str(), GENERIC_READ | GENERIC_WRITE, 
00172             FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
00173             0, NULL);
00174         
00175           if( m_hFile == INVALID_HANDLE_VALUE ) {
00176             TeErrorLog::instance().insert( UNKNOWN_ERROR_TYPE,
00177               "Temporary file creation error" );        
00178        
00179             return false;
00180           }
00181   
00182           HANDLE m_hMapping = CreateFileMapping( m_hFile, NULL, PAGE_READWRITE,
00183             0, 0, NULL );
00184               
00185           if( m_hMapping == NULL ) {
00186             CloseHandle(m_hFile);
00187         
00188             TEAGN_LOGERR( "Mapping creation error - " +
00189               getLastErrorStr() );
00190               
00191             return false;        
00192           }
00193         
00194           LPVOID m_lpszFile = (LPVOID) MapViewOfFile( m_hMapping, 
00195             FILE_MAP_ALL_ACCESS, 0, 0, 0);
00196       
00197           if( m_lpszFile == 0 ) {
00198             CloseHandle( m_hMapping );
00199             CloseHandle( m_hFile );
00200             
00201             TEAGN_LOGERR( "Mapping view creation error - " +
00202               getLastErrorStr() );
00203             
00204             return false;        
00205           }        
00206       
00207           m_hFile_ = m_hFile;
00208           m_hMapping_ = m_hMapping;
00209           m_lpszFile_ = m_lpszFile;
00210           
00211         #elif TePLATFORM == TePLATFORMCODE_LINUX || TePLATFORM == TePLATFORMCODE_AIX || TePLATFORM == TePLATFORMCODE_APPLE
00212         
00213           int m_hFile = open( disk_file_name_.c_str(), O_RDWR );
00214 
00215           if( m_hFile == -1 ) {
00216             TeErrorLog::instance().insert( UNKNOWN_ERROR_TYPE,
00217               "Temporary file creation error" );
00218             
00219             return false;         
00220           }
00221      
00222           void* m_lpszFile  =  mmap(0, (long)filesize, (PROT_READ | PROT_WRITE), 
00223             MAP_SHARED, m_hFile, 0);
00224       
00225           if( m_lpszFile == ((void*)-1) ) {
00226             close( m_hFile );
00227         
00228             TeErrorLog::instance().insert( UNKNOWN_ERROR_TYPE,
00229               "Mapping creation error" );
00230             
00231             return false;            
00232           }
00233         
00234           m_hFile_ = m_hFile;
00235           m_lpszFile_ = m_lpszFile;
00236         #else
00237           #error "Unsupported platform"
00238         #endif
00239     
00240         mapping_is_active_ = true;
00241         curr_size_ = filesize;
00242         
00243         return true;
00244       } else {     
00245         return false;
00246       }
00247     }
00248   } else {
00249     if( mapping_is_active_ ) {
00250       /* Disabling mapping */
00251       
00252       #if TePLATFORM == TePLATFORMCODE_MSWINDOWS
00253         if( ! UnmapViewOfFile( m_lpszFile_ ) ) {
00254           throw TeException( UNKNOWN_ERROR_TYPE, "Unable to unmap disk file",
00255             false );
00256         }
00257           
00258         CloseHandle( m_hMapping_ );
00259         CloseHandle( m_hFile_ );
00260       #elif TePLATFORM == TePLATFORMCODE_LINUX || TePLATFORM == TePLATFORMCODE_AIX || TePLATFORM == TePLATFORMCODE_APPLE
00261         if( munmap( m_lpszFile_ , (long)curr_size_ ) == -1) {
00262           throw TeException( UNKNOWN_ERROR_TYPE, "Unable to unmap disk file",
00263             false );
00264         }
00265             
00266         close(m_hFile_);
00267       #else
00268         #error "Unsupported platform"
00269       #endif
00270       
00271       mapping_is_active_ = false;
00272       curr_size_ = 0;
00273     }
00274         
00275     return true;
00276   }
00277 }
00278 
00279 
00280 void* TeMappedMemory::getPointer() const
00281 {
00282   TEAGN_TRUE_OR_THROW( mapping_is_active_,
00283     "Trying to access an inactive mapping" );
00284     
00285   return m_lpszFile_;
00286 }
00287 
00288 
00289 std::string TeMappedMemory::getFileName() const
00290 {
00291   TEAGN_TRUE_OR_THROW( mapping_is_active_,
00292     "Trying to access an inactive mapping" );
00293     
00294   return disk_file_name_;
00295 }
00296 
00297 
00298 bool TeMappedMemory::createNewDiskFile( const std::string& filename,
00299   unsigned long int size ) const
00300 {
00301   #if TePLATFORM == TePLATFORMCODE_MSWINDOWS
00302     int m_hFile = open( filename.c_str(),_O_RDWR|_O_CREAT,
00303       _S_IREAD | _S_IWRITE);
00304 
00305     if( m_hFile == -1 ) {
00306       TeErrorLog::instance().insert( UNKNOWN_ERROR_TYPE,
00307         "Temporary file creation error" );
00308               
00309       return false;         
00310     }
00311     
00312     off_t seek_off = ( off_t )( size - 1 );
00313           
00314     if( lseek(m_hFile, seek_off, SEEK_SET) == -1 ) {
00315       close( m_hFile );
00316           
00317       TeErrorLog::instance().insert( UNKNOWN_ERROR_TYPE,
00318         "Temporary file seek error" );
00319               
00320       return false;           
00321     }
00322         
00323     unsigned char c = '\0';
00324     
00325 
00326     if( write( m_hFile, (void*)&c, sizeof( unsigned char ) ) == -1 ) {
00327       close( m_hFile );
00328           
00329       TeErrorLog::instance().insert( UNKNOWN_ERROR_TYPE,
00330         "Temporary file write error" );
00331               
00332       return false;            
00333     }  
00334     
00335     close( m_hFile );  
00336   #elif TePLATFORM == TePLATFORMCODE_LINUX || TePLATFORM == TePLATFORMCODE_AIX || TePLATFORM == TePLATFORMCODE_APPLE
00337     int m_hFile = open( filename.c_str(),O_RDWR|O_CREAT,S_IRWXU);
00338 
00339     if( m_hFile == -1 ) {
00340       TeErrorLog::instance().insert( UNKNOWN_ERROR_TYPE,
00341         "Temporary file creation error" );
00342               
00343       return false;         
00344     }
00345     
00346     off_t seek_off = ( off_t )( size - 1 );
00347           
00348     if( lseek(m_hFile, seek_off, SEEK_SET) == -1 ) {
00349       close( m_hFile );
00350           
00351       TeErrorLog::instance().insert( UNKNOWN_ERROR_TYPE,
00352         "Temporary file seek error" );
00353               
00354       return false;           
00355     }
00356         
00357     unsigned char c = '\0';
00358     
00359 
00360     if( write( m_hFile, (void*)&c, sizeof( unsigned char ) ) == -1 ) {
00361       close( m_hFile );
00362           
00363       TeErrorLog::instance().insert( UNKNOWN_ERROR_TYPE,
00364         "Temporary file write error" );
00365               
00366       return false;            
00367     }  
00368     
00369     close( m_hFile );
00370   #else
00371     #error "Unsupported platform"
00372   #endif
00373   
00374   return true;
00375 }
00376 
00377 
00378 std::string TeMappedMemory::getLastErrorStr()
00379 {
00380   std::string error_string;
00381   
00382   #if TePLATFORM == TePLATFORMCODE_MSWINDOWS
00383   
00384     LPVOID lpMsgBuf = 0;    
00385     DWORD dw = GetLastError();
00386     int written_chars_nmb = 0;
00387     
00388     written_chars_nmb = FormatMessage(
00389           FORMAT_MESSAGE_ALLOCATE_BUFFER |
00390             FORMAT_MESSAGE_FROM_SYSTEM | 
00391             FORMAT_MESSAGE_IGNORE_INSERTS,
00392           NULL,
00393           dw,
00394           0,
00395           (LPTSTR) &lpMsgBuf,
00396           1024, 
00397           NULL );
00398           
00399     if( written_chars_nmb > 0 ) {
00400       int str_size = MIN( 1024, 2 * written_chars_nmb );
00401       error_string = std::string( ( (char*)lpMsgBuf ), 1024 );
00402     }
00403     
00404     if( lpMsgBuf ) {
00405       LocalFree(lpMsgBuf);
00406     }
00407     
00408   #elif TePLATFORM == TePLATFORMCODE_LINUX || TePLATFORM == TePLATFORMCODE_AIX || TePLATFORM == TePLATFORMCODE_APPLE
00409   
00410   #else
00411     #error "Unsuported platform"
00412   #endif
00413   
00414   return error_string;
00415 }
00416 
00417 
00418 unsigned long int TeMappedMemory::size() const
00419 {
00420   return curr_size_;
00421 }

Generated on Sun Jul 29 04:01:22 2012 for TerraLib - Development Source by  doxygen 1.5.3