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