libStatGen Software  1
MemoryMap.cpp
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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends