00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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
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
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 }