*/
#include <folly/MemoryMapping.h>
+
+#include <algorithm>
+#include <functional>
+#include <utility>
+
#include <folly/Format.h>
-#include <folly/Portability.h>
#ifdef __linux__
#include <folly/experimental/io/HugePages.h>
MemoryMapping::MemoryMapping(const char* name, off_t offset, off_t length,
Options options)
- : MemoryMapping(File(name), offset, length, options) { }
+ : MemoryMapping(File(name, options.writable ? O_RDWR : O_RDONLY),
+ offset,
+ length,
+ options) { }
MemoryMapping::MemoryMapping(int fd, off_t offset, off_t length,
Options options)
bool memOpInChunks(std::function<int(void*, size_t)> op,
void* mem, size_t bufSize, off_t pageSize,
size_t& amountSucceeded) {
+#ifdef _MSC_VER
+ // MSVC doesn't have this problem, and calling munmap many times
+ // with the same address is a bad idea with the windows implementation.
+ int ret = op(mem, bufSize);
+ if (ret == 0) {
+ amountSucceeded = bufSize;
+ }
+ return ret == 0;
+#else
// unmap/mlock/munlock take a kernel semaphore and block other threads from
// doing other memory operations. If the size of the buffer is big the
// semaphore can be down for seconds (for benchmarks see
}
return true;
+#endif
}
} // anonymous namespace
return true;
}
- auto msg(folly::format(
- "mlock({}) failed at {}",
- mapLength_, amountSucceeded).str());
+ auto msg =
+ folly::sformat("mlock({}) failed at {}", mapLength_, amountSucceeded);
if (lock == LockMode::TRY_LOCK && (errno == EPERM || errno == ENOMEM)) {
PLOG(WARNING) << msg;
PLOG(FATAL) << msg;
}
+#ifndef _MSC_VER
// only part of the buffer was mlocked, unlock it back
if (!memOpInChunks(::munlock, mapStart_, amountSucceeded, options_.pageSize,
amountSucceeded)) {
PLOG(WARNING) << "munlock()";
}
+#endif
return false;
}
size_t amountSucceeded = 0;
if (!memOpInChunks(::munmap, mapStart_, mapLength_, options_.pageSize,
amountSucceeded)) {
- PLOG(FATAL) << folly::format(
- "munmap({}) failed at {}",
- mapLength_, amountSucceeded).str();
+ PLOG(FATAL) << folly::format("munmap({}) failed at {}",
+ mapLength_, amountSucceeded);
}
}
}
-void MemoryMapping::advise(int advice) const {
- if (mapLength_ && ::madvise(mapStart_, mapLength_, advice)) {
- PLOG(WARNING) << "madvise()";
+void MemoryMapping::advise(int advice) const { advise(advice, 0, mapLength_); }
+
+void MemoryMapping::advise(int advice, size_t offset, size_t length) const {
+ CHECK_LE(offset + length, mapLength_)
+ << " offset: " << offset
+ << " length: " << length
+ << " mapLength_: " << mapLength_;
+
+ // Include the entire start page: round down to page boundary.
+ const auto offMisalign = offset % options_.pageSize;
+ offset -= offMisalign;
+ length += offMisalign;
+
+ // Round the last page down to page boundary.
+ if (offset + length != size_t(mapLength_)) {
+ length -= length % options_.pageSize;
}
+
+ if (length == 0) {
+ return;
+ }
+
+ char* mapStart = static_cast<char*>(mapStart_) + offset;
+ PLOG_IF(WARNING, ::madvise(mapStart, length, advice)) << "madvise";
}
MemoryMapping& MemoryMapping::operator=(MemoryMapping other) {