diff --git a/llvm/include/llvm/Support/FileSystem.h b/llvm/include/llvm/Support/FileSystem.h --- a/llvm/include/llvm/Support/FileSystem.h +++ b/llvm/include/llvm/Support/FileSystem.h @@ -1337,6 +1337,9 @@ /// behavior. const char *const_data() const; + /// Write changes to disk and synchronize. Equivalent to POSIX msync. + std::error_code sync() const; + /// \returns The minimum alignment offset must be. static int alignment(); }; diff --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc --- a/llvm/lib/Support/Unix/Path.inc +++ b/llvm/lib/Support/Unix/Path.inc @@ -885,6 +885,14 @@ #endif } +std::error_code mapped_file_region::sync() const { + assert(Mapping && "Mapping failed but used anyway!"); + assert(Mode == readwrite && "sync only valid for readwrite regions!"); + if (::msync(Mapping, Size, MS_SYNC)) + return std::error_code(errno, std::generic_category()); + return std::error_code(); +} + int mapped_file_region::alignment() { return Process::getPageSizeEstimate(); } diff --git a/llvm/lib/Support/Windows/Path.inc b/llvm/lib/Support/Windows/Path.inc --- a/llvm/lib/Support/Windows/Path.inc +++ b/llvm/lib/Support/Windows/Path.inc @@ -963,6 +963,16 @@ void mapped_file_region::dontNeedImpl() {} +std::error_code mapped_file_region::sync() const { + assert(Mapping && "Mapping failed but used anyway!"); + assert(Mode == readwrite && "sync only valid for readwrite regions!"); + if (!::FlushViewOfFile(Mapping, Size)) + return mapWindowsError(GetLastError()); + if (!::FlushFileBuffers(FileHandle)) + return mapWindowsError(GetLastError()); + return std::error_code(); +} + int mapped_file_region::alignment() { SYSTEM_INFO SysInfo; ::GetSystemInfo(&SysInfo); diff --git a/llvm/unittests/Support/Path.cpp b/llvm/unittests/Support/Path.cpp --- a/llvm/unittests/Support/Path.cpp +++ b/llvm/unittests/Support/Path.cpp @@ -1463,6 +1463,33 @@ ASSERT_NO_ERROR(fs::remove(TempPath)); } +TEST_F(FileSystemTest, FileMappingSync) { + // Create a temp file. + int FD; + SmallString<64> TempPath; + ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "temp", FD, TempPath)); + StringRef Content("hello there"); + ASSERT_NO_ERROR(fs::resize_file_before_mapping_readwrite(FD, Content.size())); + + { + // Map in the file and write some content. + std::error_code EC; + fs::mapped_file_region mfr(fs::convertFDToNativeFile(FD), + fs::mapped_file_region::readwrite, + Content.size(), 0, EC); + ASSERT_NO_ERROR(EC); + ASSERT_EQ(close(FD), 0); + std::copy(Content.begin(), Content.end(), mfr.data()); + + // Synchronize and check the contents before unmapping. + mfr.sync(); + auto Buffer = MemoryBuffer::getFile(TempPath); + ASSERT_TRUE((bool)Buffer); + ASSERT_EQ(Content, Buffer->get()->getBuffer()); + } + ASSERT_NO_ERROR(fs::remove(TempPath)); +} + TEST(Support, NormalizePath) { // Input, Expected Win, Expected Posix using TestTuple = std::tuple;