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" {
14 }
15
18 extern "C" __declspec(dllimport) int __stdcall UnmapViewOfFile(void const* lpBaseAddress);
19 extern "C" __declspec(dllimport) int __stdcall CloseHandle(void* hObject);
20 extern "C" __declspec(dllimport) unsigned long __stdcall GetLastError();
21 extern "C" __declspec(dllimport) void* __stdcall CreateFileW(const wchar_t*, unsigned long, unsigned long, LPSECURITY_ATTRIBUTES, unsigned long, unsigned long, void*);
22
23 extern "C" struct SYSTEM_INFO {
24 union {
25 unsigned long dwOemId; // Obsolete field...do not use
26 struct {
27 unsigned short wProcessorArchitecture;
28 unsigned short wReserved;
31 unsigned long dwPageSize;
34 unsigned long* dwActiveProcessorMask;
35 unsigned long dwNumberOfProcessors;
36 unsigned long dwProcessorType;
37 unsigned long dwAllocationGranularity;
38 unsigned short wProcessorLevel;
39 unsigned short wProcessorRevision;
40 };
41
43 extern "C" __declspec(dllimport) void* __stdcall CreateFileMappingW(void* hFile, void* lpFileMappingAttributes, unsigned long flProtect, unsigned long dwMaximumSizeHigh, unsigned long dwMaximumSizeLow, const wchar_t* lpName);
44 extern "C" __declspec(dllimport) void* __stdcall MapViewOfFile(void* hFileMappingObject, unsigned long dwDesiredAccess, unsigned long dwFileOffsetHigh, unsigned long dwFileOffsetLow, size_t dwNumberOfBytesToMap);
45#endif
46
47 namespace
48 {
49 inline std::error_code last_error() noexcept
50 {
51 std::error_code error;
52#ifdef _WIN32
53 error.assign(GetLastError(), std::system_category());
54#else
55 error.assign(errno, std::system_category());
56#endif
57 return error;
58 }
59
60 inline size_t page_size() noexcept
61 {
62 static const size_t page_size = []
63 {
64#ifdef _WIN32
67 return SystemInfo.dwAllocationGranularity;
68#else
69 return sysconf(_SC_PAGE_SIZE);
70#endif
71 }();
72 return page_size;
73 }
74
75 inline size_t make_offset_page_aligned(size_t offset) noexcept
76 {
77 const size_t page_size_ = page_size();
78 // Use integer division to round down to the nearest page alignment.
79 return offset / page_size_ * page_size_;
80 }
81
82 inline unsigned long int64_high(int64_t n) noexcept
83 {
84 return n >> 32;
85 }
86
87 inline unsigned long int64_low(int64_t n) noexcept
88 {
89 return n & 0xffffffff;
90 }
91 }
92
93 template <typename VALUE_TYPE>
94 inline void mmap_sink<VALUE_TYPE>::sync(std::error_code& error) noexcept
95 {
96 error.clear();
97 if (!this->is_open())
98 {
99 error = std::make_error_code(std::errc::bad_file_descriptor);
100 return;
101 }
102
103 if (this->data())
104 {
105#ifdef _WIN32
106 if (FlushViewOfFile(get_mapping_start(), this->mapped_length_) == 0 || FlushFileBuffers(this->file_handle_) == 0)
107#else // POSIX
108 if (::msync(get_mapping_start(), mapped_length_, MS_SYNC) != 0)
109#endif
110 {
111 error = last_error();
112 return;
113 }
114 }
115
116#ifdef _WIN32
117 if (FlushFileBuffers(this->file_handle_) == 0)
118 {
119 error = last_error();
120 }
121#endif
122 }
123
124 template <typename VALUE_TYPE>
125 inline file_handle_type mmap_sink<VALUE_TYPE>::open_file(const std::filesystem::path& path, std::error_code& error) noexcept
126 {
127 if (path.empty())
128 {
129 error = std::make_error_code(std::errc::invalid_argument);
130 return invalid_handle;
131 }
132
133#ifdef _WIN32
134 const auto handle = CreateFileW(path.c_str(), (0x80000000L) | (0x40000000L), 0x00000001 | 0x00000002, 0, 3, 0x00000080, 0);
135#else // POSIX
136 const auto handle = ::open(c_str(path), O_RDWR);
137#endif
138 if (handle == invalid_handle)
139 error = last_error();
140
141 return handle;
142 }
143
144 template <typename VALUE_TYPE>
145 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
146 {
148 const int64_t length_to_map = offset - aligned_offset + length;
149#ifdef _WIN32
150 const int64_t max_file_size = offset + length;
151 const auto file_mapping_handle = CreateFileMappingW(file_handle, 0, 0x04, int64_high(max_file_size), int64_low(max_file_size), 0);
152 if (file_mapping_handle == invalid_handle)
153 {
154 error = last_error();
155 return {};
156 }
157 VALUE_TYPE* mapping_start = static_cast<VALUE_TYPE*>(MapViewOfFile(file_mapping_handle, 0x0002, int64_high(aligned_offset), int64_low(aligned_offset), length_to_map));
158 if (mapping_start == nullptr)
159 {
160 CloseHandle(file_mapping_handle);
161 error = last_error();
162 return {};
163 }
164#else // POSIX
165 VALUE_TYPE* mapping_start = static_cast<VALUE_TYPE*>(::mmap(0, length_to_map, PROT_WRITE, MAP_SHARED, file_handle, aligned_offset));
167 {
168 error = last_error();
169 return {};
170 }
171#endif
172
173 mmap_context ctx{};
175 ctx.length = length;
176 ctx.mapped_length = length_to_map;
177 ctx.file_mapping_handle = file_mapping_handle;
178 return ctx;
179 }
180
181 template <typename VALUE_TYPE>
182 void basic_mmap_base<VALUE_TYPE>::unmap() noexcept
183 {
184 if (!this->is_open()) { return; }
185 // TODO do we care about errors here?
186#ifdef _WIN32
187 if (this->is_mapped())
188 {
189 UnmapViewOfFile(this->get_mapping_start());
190 CloseHandle(this->file_mapping_handle_);
191 }
192#else // POSIX
193 if (data_) { ::munmap(const_cast<pointer>(get_mapping_start()), mapped_length_); }
194#endif
195
196#ifdef _WIN32
197 CloseHandle(this->file_handle_);
198#else // POSIX
199 ::close(file_handle_);
200#endif
201
202 // Reset fields to their default values.
203 this->data_ = nullptr;
204 this->length_ = this->mapped_length_ = 0;
205 this->file_handle_ = invalid_handle;
206 this->file_mapping_handle_ = invalid_handle;
207 }
208
209 template <typename VALUE_TYPE>
210 file_handle_type mmap_source<VALUE_TYPE>::open_file(const std::filesystem::path& path, std::error_code& error) noexcept
211 {
212 error.clear();
213 if (path.empty())
214 {
215 error = std::make_error_code(std::errc::invalid_argument);
216 return invalid_handle;
217 }
218#ifdef _WIN32
219 const auto handle = CreateFileW(path.c_str(), (0x80000000L), 0x00000001 | 0x00000002, 0, 3, 0x00000080, 0);
220#else // POSIX
221 const auto handle = ::open(c_str(path), O_RDONLY);
222#endif
223 if (handle == invalid_handle)
224 {
225 error = last_error();
226 }
227 return handle;
228 }
229
230 template <typename VALUE_TYPE>
231 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
232 {
234 const int64_t length_to_map = offset - aligned_offset + length;
235#ifdef _WIN32
236 const int64_t max_file_size = offset + length;
237 const auto file_mapping_handle = CreateFileMappingW(file_handle, 0, 0x02, int64_high(max_file_size), int64_low(max_file_size), 0);
238 if (file_mapping_handle == invalid_handle)
239 {
240 error = last_error();
241 return {};
242 }
243 auto mapping_start = static_cast<VALUE_TYPE*>(MapViewOfFile(file_mapping_handle, 0x0004, int64_high(aligned_offset), int64_low(aligned_offset), length_to_map));
244 if (mapping_start == nullptr)
245 {
246 // Close file handle if mapping it failed.
247 CloseHandle(file_mapping_handle);
248 error = last_error();
249 return {};
250 }
251#else // POSIX
252 auto mapping_start = static_cast<VALUE_TYPE*>(::mmap(0, length_to_map, PROT_READ, MAP_SHARED, file_handle, aligned_offset));
254 {
255 error = last_error();
256 return {};
257 }
258#endif
259
260 mmap_context ctx{};
262 ctx.length = length;
263 ctx.mapped_length = length_to_map;
264 ctx.file_mapping_handle = file_mapping_handle;
265 return ctx;
266 }
267}
constexpr auto bit_count
Equal to the number of bits in the type.
Definition bits.h:33
Primary namespace for everything in this library.
Definition align+rec2.h:10