|
5 | 5 | #include <fcntl.h> // for open, O_RDONLY
|
6 | 6 | #include <sys/mman.h> // for mmap, mmap64, munmap
|
7 | 7 | #include <sys/stat.h>
|
8 |
| -#include <unistd.h> // for close |
| 8 | +#include <unistd.h> // for close, getpagesize |
| 9 | +#elif defined(_MSC_VER) |
| 10 | +#include <windows.h> |
9 | 11 | #endif // defined(__unix__)
|
| 12 | + |
10 | 13 | #include <algorithm>
|
11 | 14 | #include <cerrno> // for errno
|
12 | 15 | #include <cstdio>
|
@@ -171,33 +174,69 @@ std::size_t PadPageForMmap(std::size_t file_bytes, dmlc::Stream* fo) {
|
171 | 174 | return padded;
|
172 | 175 | }
|
173 | 176 |
|
174 |
| -void* PrivateMmapStream::Open(StringView path, bool read_only, std::size_t offset, |
| 177 | +struct PrivateMmapStream::MMAPFile { |
| 178 | +#if defined(_MSC_VER) |
| 179 | + HANDLE fd; |
| 180 | +#else |
| 181 | + std::int32_t fd; |
| 182 | +#endif |
| 183 | + std::string path; |
| 184 | +}; |
| 185 | + |
| 186 | +PrivateMmapStream::PrivateMmapStream(std::string path, bool read_only, std::size_t offset, |
| 187 | + std::size_t length) |
| 188 | + : MemoryFixSizeBuffer{Open(std::move(path), read_only, offset, length), length} {} |
| 189 | + |
| 190 | +void* PrivateMmapStream::Open(std::string path, bool read_only, std::size_t offset, |
175 | 191 | std::size_t length) {
|
176 |
| - fd_ = open(path.c_str(), O_RDONLY); |
177 |
| - CHECK_GE(fd_, 0) << "Failed to open:" << path << ". " << strerror(errno); |
| 192 | +#if defined(_MSC_VER) |
| 193 | + HANDLE fd = CreateFile(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, |
| 194 | + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, nullptr); |
| 195 | + CHECK_NE(fd, INVALID_HANDLE_VALUE) << "Failed to open:" << path; |
| 196 | +#else |
| 197 | + auto fd = open(path.c_str(), O_RDONLY); |
| 198 | +#endif |
| 199 | + CHECK_GE(fd, 0) << "Failed to open:" << path << ". " << strerror(errno); |
| 200 | + handle_ = std::make_unique<MMAPFile>(fd, std::move(path)); |
178 | 201 |
|
179 |
| - char* ptr{nullptr}; |
| 202 | + void* ptr{nullptr}; |
| 203 | +#if defined(__linux__) || defined(__GLIBC__) |
180 | 204 | int prot{PROT_READ};
|
181 | 205 | if (!read_only) {
|
182 | 206 | prot |= PROT_WRITE;
|
183 | 207 | }
|
184 |
| -#if defined(__linux__) || defined(__GLIBC__) |
185 |
| - ptr = reinterpret_cast<char*>(mmap64(nullptr, length, prot, MAP_PRIVATE, fd_, offset)); |
| 208 | + ptr = reinterpret_cast<char*>(mmap64(nullptr, length, prot, MAP_PRIVATE, handle_->fd, offset)); |
| 209 | + CHECK_NE(ptr, MAP_FAILED) << "Failed to map: " << handle_->path << ". " << strerror(errno); |
186 | 210 | #elif defined(_MSC_VER)
|
187 |
| - LOG(FATAL) << "External memory is not implemented for Windows."; |
| 211 | + auto file_size = GetFileSize(handle_->fd, nullptr); |
| 212 | + DWORD access = read_only ? PAGE_READONLY : PAGE_READWRITE; |
| 213 | + auto map_file = CreateFileMapping(handle_->fd, nullptr, access, 0, file_size, nullptr); |
| 214 | + access = read_only ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS; |
| 215 | + ptr = MapViewOfFile(map_file, access, 0, offset, length); |
| 216 | + CHECK_NE(ptr, nullptr) << "Failed to map: " << handle_->path << ". " << GetLastError(); |
188 | 217 | #else
|
189 | 218 | CHECK_LE(offset, std::numeric_limits<off_t>::max())
|
190 | 219 | << "File size has exceeded the limit on the current system.";
|
| 220 | + int prot{PROT_READ}; |
| 221 | + if (!read_only) { |
| 222 | + prot |= PROT_WRITE; |
| 223 | + } |
191 | 224 | ptr = reinterpret_cast<char*>(mmap(nullptr, length, prot, MAP_PRIVATE, fd_, offset));
|
| 225 | + CHECK_NE(ptr, MAP_FAILED) << "Failed to map: " << handle_->path << ". " << strerror(errno); |
192 | 226 | #endif // defined(__linux__)
|
193 |
| - CHECK_NE(ptr, MAP_FAILED) << "Failed to map: " << path << ". " << strerror(errno); |
194 | 227 | return ptr;
|
195 | 228 | }
|
196 | 229 |
|
197 | 230 | PrivateMmapStream::~PrivateMmapStream() {
|
| 231 | + CHECK(handle_); |
| 232 | +#if defined(_MSC_VER) |
| 233 | + CHECK(UnmapViewOfFile(p_buffer_)) "Faled to munmap." << handle_->path << ". " << GetLastError(); |
| 234 | + CloseHandle(handle_->fd); |
| 235 | +#else |
198 | 236 | CHECK_NE(munmap(p_buffer_, buffer_size_), -1)
|
199 |
| - << "Faled to munmap." << path_ << ". " << strerror(errno); |
200 |
| - CHECK_NE(close(fd_), -1) << "Faled to close: " << path_ << ". " << strerror(errno); |
| 237 | + << "Faled to munmap." << handle_->path << ". " << strerror(errno); |
| 238 | + CHECK_NE(close(fd_), -1) << "Faled to close: " << handle_->path << ". " << strerror(errno); |
| 239 | +#endif |
201 | 240 | }
|
202 | 241 | } // namespace common
|
203 | 242 | } // namespace xgboost
|
0 commit comments