header_utils
Loading...
Searching...
No Matches
mmap_impl.h
1
4
5#pragma once
6
7#include "mmap.h"
8
9namespace ghassanpl
10{
11#if defined(_WIN32) && !defined(_WINDOWS_) && !defined(WINAPI)
12 extern "C" {
13 typedef struct _SECURITY_ATTRIBUTES SECURITY_ATTRIBUTES, * PSECURITY_ATTRIBUTES, * LPSECURITY_ATTRIBUTES;
14 }
15
16 extern "C" typedef union _LARGE_INTEGER {
17 struct {
18 unsigned int LowPart;
19 long HighPart;
20 } DUMMYSTRUCTNAME;
21 struct {
22 unsigned int LowPart;
23 long HighPart;
24 } u;
25 long long QuadPart;
26 } LARGE_INTEGER;
27
28 extern "C" __declspec(dllimport) int __stdcall FlushViewOfFile(void const* lpBaseAddress, size_t dwNumberOfBytesToFlush);
29 extern "C" __declspec(dllimport) int __stdcall FlushFileBuffers(void* hFile);
30 extern "C" __declspec(dllimport) int __stdcall UnmapViewOfFile(void const* lpBaseAddress);
31 extern "C" __declspec(dllimport) int __stdcall CloseHandle(void* hObject);
32 extern "C" __declspec(dllimport) unsigned long __stdcall GetLastError();
33 extern "C" __declspec(dllimport) void* __stdcall CreateFileW(const wchar_t*, unsigned long, unsigned long, LPSECURITY_ATTRIBUTES, unsigned long, unsigned long, void*);
34 extern "C" __declspec(dllimport) long SetFilePointerEx(void* hFile, LARGE_INTEGER liDistanceToMove, LARGE_INTEGER* lpNewFilePointer, unsigned long dwMoveMethod);
35 extern "C" __declspec(dllimport) long SetEndOfFile(void* hFile);
36
37 extern "C" struct SYSTEM_INFO {
38 union {
39 unsigned long dwOemId; // Obsolete field...do not use
40 struct {
41 unsigned short wProcessorArchitecture;
42 unsigned short wReserved;
43 } DUMMYSTRUCTNAME;
44 } DUMMYUNIONNAME;
45 unsigned long dwPageSize;
46 void* lpMinimumApplicationAddress;
47 void* lpMaximumApplicationAddress;
48 unsigned long* dwActiveProcessorMask;
49 unsigned long dwNumberOfProcessors;
50 unsigned long dwProcessorType;
51 unsigned long dwAllocationGranularity;
52 unsigned short wProcessorLevel;
53 unsigned short wProcessorRevision;
54 };
55
56 extern "C" __declspec(dllimport) void __stdcall GetSystemInfo(SYSTEM_INFO * lpSystemInfo);
57 extern "C" __declspec(dllimport) void* __stdcall CreateFileMappingW(void* hFile, void* lpFileMappingAttributes, unsigned long flProtect, unsigned long dwMaximumSizeHigh, unsigned long dwMaximumSizeLow, const wchar_t* lpName);
58 extern "C" __declspec(dllimport) void* __stdcall MapViewOfFile(void* hFileMappingObject, unsigned long dwDesiredAccess, unsigned long dwFileOffsetHigh, unsigned long dwFileOffsetLow, size_t dwNumberOfBytesToMap);
59#endif
60
61 namespace
62 {
63 inline std::error_code last_error() noexcept
64 {
65 std::error_code error;
66#ifdef _WIN32
67 error.assign(GetLastError(), std::system_category());
68#else
69 error.assign(errno, std::system_category());
70#endif
71 return error;
72 }
73
74 inline size_t page_size() noexcept
75 {
76 static const size_t page_size = []
77 {
78#ifdef _WIN32
79 SYSTEM_INFO SystemInfo{};
80 GetSystemInfo(&SystemInfo);
81 return SystemInfo.dwAllocationGranularity;
82#else
83 return sysconf(_SC_PAGE_SIZE);
84#endif
85 }();
86 return page_size;
87 }
88
89 inline size_t make_offset_page_aligned(size_t offset) noexcept
90 {
91 const size_t page_size_ = page_size();
92 // Use integer division to round down to the nearest page alignment.
93 return offset / page_size_ * page_size_;
94 }
95
96 inline unsigned long int64_high(int64_t n) noexcept
97 {
98 return n >> 32;
99 }
100
101 inline unsigned long int64_low(int64_t n) noexcept
102 {
103 return n & 0xffffffff;
104 }
105 }
106
107 namespace detail
108 {
109 inline bool create_file(std::filesystem::path const& path, size_t size, std::error_code& error) noexcept
110 {
111#ifdef _WIN32
112 auto file = CreateFileW(path.c_str(), (0x40000000L), 0x00000001 | 0x00000002, 0, 4, 0x00000080, 0);
113 if (file == nullptr)
114 {
115 error = last_error();
116 return false;
117 }
118 if (SetFilePointerEx(file, LARGE_INTEGER{.QuadPart = int64_t(size)}, nullptr, 0) == 0)
119 {
120 error = last_error();
121 CloseHandle(file);
122 return false;
123 }
124 if (SetEndOfFile(file) == 0)
125 {
126 error = last_error();
127 CloseHandle(file);
128 return false;
129 }
130 CloseHandle(file);
131 return true;
132#endif
133 }
134 }
135
136 template <typename VALUE_TYPE>
137 void mmap_sink<VALUE_TYPE>::sync(std::error_code& error) noexcept
138 {
139 error.clear();
140 if (!this->is_open())
141 {
142 error = std::make_error_code(std::errc::bad_file_descriptor);
143 return;
144 }
145
146 if (this->data())
147 {
148#ifdef _WIN32
149 if (FlushViewOfFile(get_mapping_start(), this->mapped_length_) == 0 || FlushFileBuffers(this->file_handle_) == 0)
150#else // POSIX
151 if (::msync(get_mapping_start(), mapped_length_, MS_SYNC) != 0)
152#endif
153 {
154 error = last_error();
155 return;
156 }
157 }
158
159#ifdef _WIN32
160 if (FlushFileBuffers(this->file_handle_) == 0)
161 {
162 error = last_error();
163 }
164#endif
165 }
166
167 template <typename VALUE_TYPE>
168 file_handle_type mmap_sink<VALUE_TYPE>::open_file(const std::filesystem::path& path, std::error_code& error) noexcept
169 {
170 if (path.empty())
171 {
172 error = std::make_error_code(std::errc::invalid_argument);
173 return invalid_handle;
174 }
175
176#ifdef _WIN32
177 const auto handle = CreateFileW(path.c_str(), (0x80000000L) | (0x40000000L), 0x00000001 | 0x00000002, 0, 3, 0x00000080, 0);
178#else // POSIX
179 const auto handle = ::open(c_str(path), O_RDWR);
180#endif
181 if (handle == invalid_handle)
182 error = last_error();
183
184 return handle;
185 }
186
187 template <typename VALUE_TYPE>
188 typename mmap_sink<VALUE_TYPE>::mmap_context mmap_sink<VALUE_TYPE>::memory_map(const file_handle_type file_handle, const int64_t offset, const int64_t length, std::error_code& error) noexcept
189 {
190 const int64_t aligned_offset = make_offset_page_aligned(offset);
191 const int64_t length_to_map = offset - aligned_offset + length;
192#ifdef _WIN32
193 const int64_t max_file_size = offset + length;
194 const auto file_mapping_handle = CreateFileMappingW(file_handle, 0, 0x04, int64_high(max_file_size), int64_low(max_file_size), 0);
195 if (file_mapping_handle == invalid_handle)
196 {
197 error = last_error();
198 return {};
199 }
200 VALUE_TYPE* mapping_start = static_cast<VALUE_TYPE*>(MapViewOfFile(file_mapping_handle, 0x0002, int64_high(aligned_offset), int64_low(aligned_offset), length_to_map));
201 if (mapping_start == nullptr)
202 {
203 CloseHandle(file_mapping_handle);
204 error = last_error();
205 return {};
206 }
207#else // POSIX
208 VALUE_TYPE* mapping_start = static_cast<VALUE_TYPE*>(::mmap(0, length_to_map, PROT_WRITE, MAP_SHARED, file_handle, aligned_offset));
209 if (mapping_start == MAP_FAILED)
210 {
211 error = last_error();
212 return {};
213 }
214#endif
215
216 mmap_context ctx{};
217 ctx.data = mapping_start + offset - aligned_offset;
218 ctx.length = length;
219 ctx.mapped_length = length_to_map;
220 ctx.file_mapping_handle = file_mapping_handle;
221 return ctx;
222 }
223
224 template <typename VALUE_TYPE>
225 void basic_mmap_base<VALUE_TYPE>::unmap() noexcept
226 {
227 if (!this->is_open()) { return; }
228 // TODO do we care about errors here?
229#ifdef _WIN32
230 if (this->is_mapped())
231 {
232 UnmapViewOfFile(this->get_mapping_start());
233 CloseHandle(this->file_mapping_handle_);
234 }
235#else // POSIX
236 if (data_) { ::munmap(const_cast<pointer>(get_mapping_start()), mapped_length_); }
237#endif
238
239#ifdef _WIN32
240 CloseHandle(this->file_handle_);
241#else // POSIX
242 ::close(file_handle_);
243#endif
244
245 // Reset fields to their default values.
246 this->data_ = nullptr;
247 this->length_ = this->mapped_length_ = 0;
248 this->file_handle_ = invalid_handle;
249 this->file_mapping_handle_ = invalid_handle;
250 }
251
252 template <typename VALUE_TYPE>
253 file_handle_type mmap_source<VALUE_TYPE>::open_file(const std::filesystem::path& path, std::error_code& error) noexcept
254 {
255 error.clear();
256 if (path.empty())
257 {
258 error = std::make_error_code(std::errc::invalid_argument);
259 return invalid_handle;
260 }
261#ifdef _WIN32
262 const auto handle = CreateFileW(path.c_str(), (0x80000000L), 0x00000001 | 0x00000002, 0, 3, 0x00000080, 0);
263#else // POSIX
264 const auto handle = ::open(c_str(path), O_RDONLY);
265#endif
266 if (handle == invalid_handle)
267 {
268 error = last_error();
269 }
270 return handle;
271 }
272
273 template <typename VALUE_TYPE>
274 typename mmap_source<VALUE_TYPE>::mmap_context mmap_source<VALUE_TYPE>::memory_map(const file_handle_type file_handle, const int64_t offset, const int64_t length, std::error_code& error) noexcept
275 {
276 const int64_t aligned_offset = make_offset_page_aligned(offset);
277 const int64_t length_to_map = offset - aligned_offset + length;
278#ifdef _WIN32
279 const int64_t max_file_size = offset + length;
280 const auto file_mapping_handle = CreateFileMappingW(file_handle, 0, 0x02, int64_high(max_file_size), int64_low(max_file_size), 0);
281 if (file_mapping_handle == invalid_handle)
282 {
283 error = last_error();
284 return {};
285 }
286 auto mapping_start = static_cast<VALUE_TYPE*>(MapViewOfFile(file_mapping_handle, 0x0004, int64_high(aligned_offset), int64_low(aligned_offset), length_to_map));
287 if (mapping_start == nullptr)
288 {
289 // Close file handle if mapping it failed.
290 CloseHandle(file_mapping_handle);
291 error = last_error();
292 return {};
293 }
294#else // POSIX
295 auto mapping_start = static_cast<VALUE_TYPE*>(::mmap(0, length_to_map, PROT_READ, MAP_SHARED, file_handle, aligned_offset));
296 if (mapping_start == MAP_FAILED)
297 {
298 error = last_error();
299 return {};
300 }
301#endif
302
303 mmap_context ctx{};
304 ctx.data = mapping_start + offset - aligned_offset;
305 ctx.length = length;
306 ctx.mapped_length = length_to_map;
307 ctx.file_mapping_handle = file_mapping_handle;
308 return ctx;
309 }
310}
Primary namespace for everything in this library.
Definition align+rec2.h:10