Line data Source code
1 :
2 : /* Copyright (c) 2009-2016, 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() : ptr( nullptr ) , size( 0 ), map_( 0 ) {}
40 :
41 8 : void* init( const std::string& filename, const size_t size_ )
42 : {
43 8 : if( ptr )
44 : {
45 1 : LBWARN << "File already mapped" << std::endl;
46 1 : return nullptr;
47 : }
48 :
49 7 : init_( filename, size_ );
50 7 : return ptr;
51 : }
52 :
53 4 : void unmap()
54 : {
55 4 : if( !ptr )
56 0 : return;
57 :
58 4 : unmap_();
59 4 : ptr = nullptr;
60 4 : size = 0;
61 : }
62 :
63 : void* ptr;
64 : size_t size;
65 :
66 : private:
67 : #ifdef _WIN32
68 : void* map_;
69 :
70 : void init_( const std::string& filename, const size_t size_ )
71 : {
72 : // try to open binary file (and size it)
73 : const DWORD access = size_ ? GENERIC_READ | GENERIC_WRITE:GENERIC_READ;
74 : const DWORD create = size_ ? CREATE_ALWAYS : OPEN_EXISTING;
75 : HANDLE file = ::CreateFile( filename.c_str(), access, FILE_SHARE_READ,
76 : 0, create, FILE_ATTRIBUTE_NORMAL, 0 );
77 : if( file == INVALID_HANDLE_VALUE )
78 : {
79 : LBWARN << "Can't open " << filename << ": " << sysError <<std::endl;
80 : return;
81 : }
82 :
83 : if( size_ )
84 : {
85 : ::SetFilePointer( file, LONG(size_), PLONG(&size_)+1, FILE_BEGIN );
86 : ::SetEndOfFile( file );
87 : }
88 :
89 : // create a file mapping
90 : const DWORD mode = size_ ? PAGE_READWRITE : PAGE_READONLY;
91 : map_ = ::CreateFileMapping( file, 0, mode, 0, 0, 0 );
92 : if( !map_ )
93 : {
94 : ::CloseHandle( file );
95 : LBWARN << "File mapping failed: " << sysError << std::endl;
96 : return;
97 : }
98 :
99 : // get a view of the mapping
100 : ptr = ::MapViewOfFile( map_, size_ ? FILE_MAP_WRITE :
101 : FILE_MAP_READ, 0, 0, 0 );
102 :
103 : // get size
104 : DWORD highSize;
105 : const DWORD lowSize = ::GetFileSize( file, &highSize );
106 : size = lowSize | ( static_cast< uint64_t >( highSize ) << 32 );
107 : LBASSERT( size_ == 0 || size_ == size );
108 :
109 : ::CloseHandle( file );
110 : }
111 :
112 : void unmap_()
113 : {
114 : ::UnmapViewOfFile( ptr );
115 : ::CloseHandle( map_ );
116 : map_ = 0;
117 : }
118 :
119 : #else
120 :
121 : int map_;
122 :
123 7 : void init_( const std::string& filename, const size_t size_ )
124 : {
125 : // try to open binary file (and size it)
126 7 : const int flags = size_ ? O_RDWR | O_CREAT : O_RDONLY;
127 7 : map_ = ::open( filename.c_str(), flags, S_IRUSR | S_IWUSR );
128 7 : if( map_ < 0 )
129 : {
130 3 : LBINFO << "Can't open " << filename << ": " << sysError <<std::endl;
131 6 : return;
132 : }
133 :
134 4 : if( size_ > 0 && ::ftruncate( map_, size_ ) != 0 )
135 : {
136 0 : LBINFO << "Can't resize " << filename << ": " << sysError
137 0 : << std::endl;
138 0 : return;
139 : }
140 :
141 : // retrieve file information
142 : struct stat status;
143 4 : ::fstat( map_, &status );
144 :
145 : // create memory mapped file
146 4 : size = status.st_size;
147 4 : LBASSERTINFO( size_ == 0 || size_ == size, size << " ? " << size_ );
148 :
149 4 : const int mapFlags = size_ ? PROT_READ | PROT_WRITE : PROT_READ;
150 4 : ptr = ::mmap( 0, size, mapFlags, MAP_SHARED, map_, 0 );
151 4 : if( ptr == MAP_FAILED )
152 : {
153 0 : ::close( map_ );
154 0 : ptr = nullptr;
155 0 : size = 0;
156 0 : map_ = 0;
157 : }
158 : }
159 :
160 4 : void unmap_()
161 : {
162 4 : ::munmap( ptr, size );
163 4 : ::close( map_ );
164 4 : map_ = 0;
165 4 : }
166 : #endif
167 : };
168 : }
169 :
170 0 : MemoryMap::MemoryMap()
171 0 : : impl_( new detail::MemoryMap )
172 : {
173 0 : }
174 :
175 1 : MemoryMap::MemoryMap( const std::string& filename )
176 1 : : impl_( new detail::MemoryMap )
177 : {
178 1 : if( !map( filename ))
179 1 : LBTHROW( std::runtime_error( "Can't map file" ));
180 0 : }
181 :
182 2 : MemoryMap::MemoryMap( const std::string& filename, const size_t size )
183 2 : : impl_( new detail::MemoryMap )
184 : {
185 2 : if( !create( filename, size ))
186 1 : LBTHROW( std::runtime_error( "Can't create file" ));
187 1 : }
188 :
189 2 : MemoryMap::~MemoryMap()
190 : {
191 1 : unmap();
192 1 : delete impl_;
193 1 : }
194 :
195 4 : const void* MemoryMap::map( const std::string& filename )
196 : {
197 4 : return impl_->init( filename, 0 );
198 : }
199 :
200 1 : const void* MemoryMap::remap( const std::string& filename )
201 : {
202 1 : unmap();
203 1 : return impl_->init( filename, 0 );
204 : }
205 :
206 3 : void* MemoryMap::create( const std::string& filename, const size_t size )
207 : {
208 3 : LBASSERT( size > 0 );
209 3 : if( size == 0 )
210 0 : return nullptr;
211 :
212 3 : return impl_->init( filename, size );
213 : }
214 :
215 1 : void* MemoryMap::recreate( const std::string& filename, const size_t size )
216 : {
217 1 : unmap();
218 1 : return create( filename, size );
219 : }
220 :
221 4 : void MemoryMap::unmap()
222 : {
223 4 : impl_->unmap();
224 4 : }
225 :
226 0 : const void* MemoryMap::getAddress() const
227 : {
228 0 : return impl_->ptr;
229 : }
230 :
231 2 : void* MemoryMap::getAddress()
232 : {
233 2 : return impl_->ptr;
234 : }
235 :
236 3 : size_t MemoryMap::getSize() const
237 : {
238 3 : return impl_->size;
239 : }
240 :
241 72 : }
|