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 : }
|