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 121 : MemoryMap() : ptr( 0 ) , size( 0 ), map_( 0 ) {}
39 :
40 123 : void* init( const std::string& filename, const size_t size_ )
41 : {
42 123 : if( ptr )
43 : {
44 0 : LBWARN << "File already mapped" << std::endl;
45 0 : return 0;
46 : }
47 :
48 123 : init_( filename, size_ );
49 123 : return ptr;
50 : }
51 :
52 122 : void unmap()
53 : {
54 122 : if( !ptr )
55 122 : return;
56 :
57 122 : unmap_();
58 122 : ptr = 0;
59 122 : 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 : LBWARN << "File mapping failed: " << sysError << std::endl;
94 : return;
95 : }
96 :
97 : // get a view of the mapping
98 : ptr = ::MapViewOfFile( map_, FILE_MAP_READ, 0, 0, 0 );
99 :
100 : // get size
101 : DWORD highSize;
102 : const DWORD lowSize = ::GetFileSize( file, &highSize );
103 : size = lowSize | ( static_cast< uint64_t >( highSize ) << 32 );
104 : LBASSERT( size_ == 0 || size_ == size );
105 :
106 : ::CloseHandle( file );
107 : }
108 :
109 : void unmap_()
110 : {
111 : ::UnmapViewOfFile( ptr );
112 : ::CloseHandle( map_ );
113 : map_ = 0;
114 : }
115 :
116 : #else
117 :
118 : int map_;
119 :
120 123 : void init_( const std::string& filename, const size_t size_ )
121 : {
122 : // try to open binary file (and size it)
123 123 : const int flags = size_ ? O_RDWR | O_CREAT : O_RDONLY;
124 123 : map_ = ::open( filename.c_str(), flags, S_IRUSR | S_IWUSR );
125 123 : if( map_ < 0 )
126 : {
127 1 : LBINFO << "Can't open " << filename << ": " << sysError <<std::endl;
128 2 : return;
129 : }
130 :
131 122 : if( size_ > 0 && ::ftruncate( map_, size_ ) != 0 )
132 : {
133 0 : LBINFO << "Can't resize " << filename << ": " << sysError
134 0 : << std::endl;
135 0 : return;
136 : }
137 :
138 : // retrieve file information
139 : struct stat status;
140 122 : ::fstat( map_, &status );
141 :
142 : // create memory mapped file
143 122 : size = status.st_size;
144 122 : LBASSERTINFO( size_ == 0 || size_ == size, size << " ? " << size_ );
145 :
146 122 : const int mapFlags = size_ ? PROT_READ | PROT_WRITE : PROT_READ;
147 122 : ptr = ::mmap( 0, size, mapFlags, MAP_SHARED, map_, 0 );
148 122 : if( ptr == MAP_FAILED )
149 : {
150 0 : ::close( map_ );
151 0 : ptr = 0;
152 0 : size = 0;
153 0 : map_ = 0;
154 : }
155 : }
156 :
157 122 : void unmap_()
158 : {
159 122 : ::munmap( ptr, size );
160 122 : ::close( map_ );
161 122 : map_ = 0;
162 122 : }
163 : #endif
164 : };
165 : }
166 :
167 120 : MemoryMap::MemoryMap()
168 120 : : impl_( new detail::MemoryMap )
169 : {
170 120 : }
171 :
172 0 : MemoryMap::MemoryMap( const std::string& filename )
173 0 : : impl_( new detail::MemoryMap )
174 : {
175 0 : map( filename );
176 0 : }
177 :
178 1 : MemoryMap::MemoryMap( const std::string& filename, const size_t size )
179 1 : : impl_( new detail::MemoryMap )
180 : {
181 1 : create( filename, size );
182 1 : }
183 :
184 121 : MemoryMap::~MemoryMap()
185 : {
186 121 : unmap();
187 121 : delete impl_;
188 121 : }
189 :
190 122 : const void* MemoryMap::map( const std::string& filename )
191 : {
192 122 : return impl_->init( filename, 0 );
193 : }
194 :
195 0 : const void* MemoryMap::remap( const std::string& filename )
196 : {
197 0 : unmap();
198 0 : return impl_->init( filename, 0 );
199 : }
200 :
201 1 : void* MemoryMap::create( const std::string& filename, const size_t size )
202 : {
203 1 : LBASSERT( size > 0 );
204 1 : if( size == 0 )
205 0 : return 0;
206 :
207 1 : return impl_->init( filename, size );
208 : }
209 :
210 0 : void* MemoryMap::recreate( const std::string& filename, const size_t size )
211 : {
212 0 : unmap();
213 0 : return create( filename, size );
214 : }
215 :
216 122 : void MemoryMap::unmap()
217 : {
218 122 : impl_->unmap();
219 122 : }
220 :
221 0 : const void* MemoryMap::getAddress() const
222 : {
223 0 : return impl_->ptr;
224 : }
225 :
226 2 : void* MemoryMap::getAddress()
227 : {
228 2 : return impl_->ptr;
229 : }
230 :
231 123 : size_t MemoryMap::getSize() const
232 : {
233 123 : return impl_->size;
234 : }
235 :
236 90 : }
|