LCOV - code coverage report
Current view: top level - lunchbox - memoryMap.cpp (source / functions) Hit Total Coverage
Test: Lunchbox Lines: 76 92 82.6 %
Date: 2018-10-03 05:33:11 Functions: 20 22 90.9 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2009-2017, Stefan Eilemann <eile@equalizergraphics.com>
       3             :  *
       4             :  * This library is free software; you can redistribute it and/or modify it under
       5             :  * the terms of the GNU Lesser General Public License version 2.1 as published
       6             :  * by the Free Software Foundation.
       7             :  *
       8             :  * This library is distributed in the hope that it will be useful, but WITHOUT
       9             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
      10             :  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
      11             :  * details.
      12             :  *
      13             :  * You should have received a copy of the GNU Lesser General Public License
      14             :  * along with this library; if not, write to the Free Software Foundation, Inc.,
      15             :  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      16             :  */
      17             : 
      18             : #include "memoryMap.h"
      19             : 
      20             : #include "debug.h"
      21             : #include "os.h"
      22             : #include "types.h"
      23             : 
      24             : #include <fcntl.h>
      25             : #include <sys/stat.h>
      26             : #ifndef _WIN32
      27             : #include <sys/mman.h>
      28             : #include <unistd.h>
      29             : #endif
      30             : #include <stdexcept>
      31             : 
      32             : namespace lunchbox
      33             : {
      34             : namespace detail
      35             : {
      36             : class MemoryMap
      37             : {
      38             : public:
      39           3 :     MemoryMap()
      40           3 :         : ptr(nullptr)
      41             :         , size(0)
      42           3 :         , _map(0)
      43             : #ifdef _WIN32
      44             :         , _file(nullptr)
      45             : #endif
      46             :     {
      47           3 :     }
      48             : 
      49           8 :     void* init(const std::string& filename, const size_t size_)
      50             :     {
      51           8 :         if (ptr)
      52             :         {
      53           1 :             LBWARN << "File already mapped" << std::endl;
      54           1 :             return nullptr;
      55             :         }
      56             : 
      57           7 :         return _init(filename, size_);
      58             :     }
      59             : 
      60           4 :     void unmap()
      61             :     {
      62           4 :         if (!ptr)
      63           0 :             return;
      64             : 
      65           4 :         _unmap();
      66           4 :         ptr = nullptr;
      67           4 :         size = 0;
      68             :     }
      69             : 
      70           1 :     void* resize(const size_t size_)
      71             :     {
      72           1 :         if (!ptr)
      73           0 :             return nullptr;
      74           1 :         if (size == size_)
      75           0 :             return ptr;
      76             : 
      77             : #ifdef _WIN32
      78             :         ::UnmapViewOfFile(ptr);
      79             :         ::CloseHandle(_map);
      80             : #else
      81           1 :         ::munmap(ptr, size);
      82             : #endif
      83             : 
      84           1 :         return _mapFile(size_);
      85             :     }
      86             : 
      87             :     void* ptr;
      88             :     size_t size;
      89             : 
      90             : private:
      91             : #ifdef _WIN32
      92             :     HANDLE _file;
      93             :     void* _map;
      94             : 
      95             :     void* _init(const std::string& filename, const size_t size_)
      96             :     {
      97             :         // try to open binary file
      98             :         const DWORD access =
      99             :             size_ ? GENERIC_READ | GENERIC_WRITE : GENERIC_READ;
     100             :         const DWORD create = size_ ? CREATE_ALWAYS : OPEN_EXISTING;
     101             :         _file = ::CreateFile(filename.c_str(), access, FILE_SHARE_READ, 0,
     102             :                              create, FILE_ATTRIBUTE_NORMAL, 0);
     103             :         if (_file == INVALID_HANDLE_VALUE)
     104             :         {
     105             :             LBWARN << "Can't open " << filename << ": " << sysError
     106             :                    << std::endl;
     107             :             return nullptr;
     108             :         }
     109             :         return _mapFile(size_);
     110             :     }
     111             : 
     112             :     void* _mapFile(const size_t size_)
     113             :     {
     114             :         if (!_file)
     115             :             return nullptr;
     116             : 
     117             :         if (size_)
     118             :         {
     119             :             ::SetFilePointer(_file, LONG(size), PLONG(&size) + 1, FILE_BEGIN);
     120             :             ::SetEndOfFile(_file);
     121             :         }
     122             : 
     123             :         // create a file mapping
     124             :         const DWORD mode = size_ ? PAGE_READWRITE : PAGE_READONLY;
     125             :         _map = ::CreateFileMapping(_file, 0, mode, 0, 0, 0);
     126             :         if (!_map)
     127             :         {
     128             :             ::CloseHandle(_file);
     129             :             LBWARN << "File mapping failed: " << sysError << std::endl;
     130             :             return nullptr;
     131             :         }
     132             : 
     133             :         // get a view of the mapping
     134             :         ptr = ::MapViewOfFile(_map, size_ ? FILE_MAP_WRITE : FILE_MAP_READ, 0,
     135             :                               0, 0);
     136             : 
     137             :         // get size
     138             :         DWORD highSize;
     139             :         const DWORD lowSize = ::GetFileSize(_file, &highSize);
     140             :         size = lowSize | (static_cast<uint64_t>(highSize) << 32);
     141             :         return ptr;
     142             :     }
     143             : 
     144             :     void _unmap()
     145             :     {
     146             :         ::UnmapViewOfFile(ptr);
     147             :         ::CloseHandle(_map);
     148             :         ::CloseHandle(_file);
     149             :         _file = nullptr;
     150             :         _map = nullptr;
     151             :     }
     152             : 
     153             : #else
     154             :     int _map;
     155             : 
     156           7 :     void* _init(const std::string& filename, const size_t size_)
     157             :     {
     158             :         // try to open binary file (and size it)
     159           7 :         const int flags = size_ ? O_RDWR | O_CREAT : O_RDONLY;
     160           7 :         _map = ::open(filename.c_str(), flags, S_IRUSR | S_IWUSR);
     161           7 :         if (_map < 0)
     162             :         {
     163           9 :             LBINFO << "Can't open " << filename << ": " << sysError
     164           9 :                    << std::endl;
     165           3 :             return nullptr;
     166             :         }
     167             : 
     168           4 :         return _mapFile(size_);
     169             :     }
     170             : 
     171           5 :     void* _mapFile(const size_t size_)
     172             :     {
     173           5 :         if (size_ > 0 && ::ftruncate(_map, size_) != 0)
     174             :         {
     175           0 :             LBINFO << "Can't resize file: " << sysError << std::endl;
     176           0 :             return nullptr;
     177             :         }
     178             : 
     179             :         // retrieve file information
     180             :         struct stat status;
     181           5 :         ::fstat(_map, &status);
     182             : 
     183             :         // create memory mapped file
     184           5 :         size = status.st_size;
     185           5 :         LBASSERTINFO(size_ == 0 || size_ == size, size_ << " != " << size);
     186             : 
     187           5 :         const int mapFlags = size_ ? PROT_READ | PROT_WRITE : PROT_READ;
     188           5 :         ptr = ::mmap(0, size, mapFlags, MAP_SHARED, _map, 0);
     189           5 :         if (ptr == MAP_FAILED)
     190             :         {
     191           0 :             ::close(_map);
     192           0 :             ptr = nullptr;
     193           0 :             size = 0;
     194           0 :             _map = 0;
     195             :         }
     196           5 :         return ptr;
     197             :     }
     198             : 
     199           4 :     void _unmap()
     200             :     {
     201           4 :         ::munmap(ptr, size);
     202           4 :         ::close(_map);
     203           4 :         _map = 0;
     204           4 :     }
     205             : #endif
     206             : };
     207             : }
     208             : 
     209           0 : MemoryMap::MemoryMap()
     210           0 :     : impl_(new detail::MemoryMap)
     211             : {
     212           0 : }
     213             : 
     214           1 : MemoryMap::MemoryMap(const std::string& filename)
     215           1 :     : impl_(new detail::MemoryMap)
     216             : {
     217           1 :     if (!map(filename))
     218           1 :         LBTHROW(std::runtime_error("Can't map file"));
     219           0 : }
     220             : 
     221           2 : MemoryMap::MemoryMap(const std::string& filename, const size_t size)
     222           2 :     : impl_(new detail::MemoryMap)
     223             : {
     224           2 :     if (!create(filename, size))
     225           1 :         LBTHROW(std::runtime_error("Can't create file"));
     226           1 : }
     227             : 
     228           2 : MemoryMap::~MemoryMap()
     229             : {
     230           1 :     unmap();
     231           1 :     delete impl_;
     232           1 : }
     233             : 
     234           4 : const void* MemoryMap::map(const std::string& filename)
     235             : {
     236           4 :     return impl_->init(filename, 0);
     237             : }
     238             : 
     239           1 : const void* MemoryMap::remap(const std::string& filename)
     240             : {
     241           1 :     unmap();
     242           1 :     return impl_->init(filename, 0);
     243             : }
     244             : 
     245           3 : void* MemoryMap::create(const std::string& filename, const size_t size)
     246             : {
     247           3 :     LBASSERT(size > 0);
     248           3 :     if (size == 0)
     249           0 :         return nullptr;
     250             : 
     251           3 :     return impl_->init(filename, size);
     252             : }
     253             : 
     254           1 : void* MemoryMap::recreate(const std::string& filename, const size_t size)
     255             : {
     256           1 :     unmap();
     257           1 :     return create(filename, size);
     258             : }
     259             : 
     260           1 : void* MemoryMap::resize(size_t size)
     261             : {
     262           1 :     return impl_->resize(size);
     263             : }
     264             : 
     265           4 : void MemoryMap::unmap()
     266             : {
     267           4 :     impl_->unmap();
     268           4 : }
     269             : 
     270           0 : const void* MemoryMap::getAddress() const
     271             : {
     272           0 :     return impl_->ptr;
     273             : }
     274             : 
     275           3 : void* MemoryMap::getAddress()
     276             : {
     277           3 :     return impl_->ptr;
     278             : }
     279             : 
     280           3 : size_t MemoryMap::getSize() const
     281             : {
     282           3 :     return impl_->size;
     283             : }
     284          75 : }

Generated by: LCOV version 1.11