diff options
author | Alexey Salmin <[email protected]> | 2022-02-10 16:49:37 +0300 |
---|---|---|
committer | Daniil Cherednik <[email protected]> | 2022-02-10 16:49:37 +0300 |
commit | 71af077a5dfe7e9f932a508422c2dac81a57ebc0 (patch) | |
tree | 5d5cb817648f650d76cf1076100726fd9b8448e8 /util/system | |
parent | 3c5b1607b38f637d2f3313791ed25c2e080d2647 (diff) |
Restoring authorship annotation for Alexey Salmin <[email protected]>. Commit 2 of 2.
Diffstat (limited to 'util/system')
-rw-r--r-- | util/system/direct_io.cpp | 8 | ||||
-rw-r--r-- | util/system/direct_io_ut.cpp | 8 | ||||
-rw-r--r-- | util/system/filemap.cpp | 120 | ||||
-rw-r--r-- | util/system/filemap.h | 12 | ||||
-rw-r--r-- | util/system/filemap_ut.cpp | 126 | ||||
-rw-r--r-- | util/system/mincore.cpp | 60 | ||||
-rw-r--r-- | util/system/mincore.h | 76 | ||||
-rw-r--r-- | util/system/mincore_ut.cpp | 90 | ||||
-rw-r--r-- | util/system/unaligned_mem.h | 8 | ||||
-rw-r--r-- | util/system/unaligned_mem_ut.cpp | 146 | ||||
-rw-r--r-- | util/system/ut/ya.make | 8 |
11 files changed, 331 insertions, 331 deletions
diff --git a/util/system/direct_io.cpp b/util/system/direct_io.cpp index 8a0d453bdd4..f59c54b0cbd 100644 --- a/util/system/direct_io.cpp +++ b/util/system/direct_io.cpp @@ -34,10 +34,10 @@ namespace { } else if (linuxVersionCode < KERNEL_VERSION(2, 6, 0)) { Alignment = NSystemInfo::GetPageSize(); } else { - // Default alignment used to be 512, but most modern devices rely on 4k physical blocks. - // 4k alignment works well for both 512 and 4k blocks and doesn't require 512e support in the kernel. - // See IGNIETFERRO-946. - Alignment = 4096; + // Default alignment used to be 512, but most modern devices rely on 4k physical blocks. + // 4k alignment works well for both 512 and 4k blocks and doesn't require 512e support in the kernel. + // See IGNIETFERRO-946. + Alignment = 4096; } #endif } diff --git a/util/system/direct_io_ut.cpp b/util/system/direct_io_ut.cpp index d6f5e26ffa3..839c3de7ca4 100644 --- a/util/system/direct_io_ut.cpp +++ b/util/system/direct_io_ut.cpp @@ -1,7 +1,7 @@ #include <library/cpp/testing/unittest/registar.h> #include <util/generic/yexception.h> -#include <util/system/fs.h> +#include <util/system/fs.h> #include <util/system/tempfile.h> #include <util/random/random.h> @@ -11,7 +11,7 @@ static const char* FileName_("./test.file"); Y_UNIT_TEST_SUITE(TDirectIoTestSuite) { Y_UNIT_TEST(TestDirectFile) { - TDirectIOBufferedFile file(FileName_, RdWr | Direct | Seq | CreateAlways, 1 << 15); + TDirectIOBufferedFile file(FileName_, RdWr | Direct | Seq | CreateAlways, 1 << 15); TVector<ui64> data((1 << 15) + 1); TVector<ui64> readResult(data.size()); for (auto& i : data) { @@ -31,7 +31,7 @@ Y_UNIT_TEST_SUITE(TDirectIoTestSuite) { } } file.Finish(); - TDirectIOBufferedFile fileNew(FileName_, RdOnly | Direct | Seq | OpenAlways, 1 << 15); + TDirectIOBufferedFile fileNew(FileName_, RdOnly | Direct | Seq | OpenAlways, 1 << 15); for (int i = 0; i < 1000; ++i) { size_t readPos = RandomNumber(data.size()); size_t readCount = RandomNumber(data.size() - readPos); @@ -49,7 +49,7 @@ Y_UNIT_TEST_SUITE(TDirectIoTestSuite) { for (size_t i = 0; i < readCount; ++i) { UNIT_ASSERT_VALUES_EQUAL(readResult[i], data[i]); } - NFs::Remove(FileName_); + NFs::Remove(FileName_); } void TestHugeFile(size_t size) { diff --git a/util/system/filemap.cpp b/util/system/filemap.cpp index f6e3a7f5b78..7454a4cb948 100644 --- a/util/system/filemap.cpp +++ b/util/system/filemap.cpp @@ -126,7 +126,7 @@ void NPrivate::Precharge(const void* data, size_t dataSize, size_t off, size_t s class TMemoryMap::TImpl: public TAtomicRefCount<TImpl> { public: - inline void CreateMapping() { + inline void CreateMapping() { #if defined(_win_) Mapping_ = nullptr; if (Length_) { @@ -134,7 +134,7 @@ public: (Mode_ & oAccessMask) == TFileMap::oRdWr ? PAGE_READWRITE : PAGE_READONLY, (DWORD)(Length_ >> 32), (DWORD)(Length_ & 0xFFFFFFFF), nullptr); if (Mapping_ == nullptr) { - ythrow yexception() << "Can't create file mapping of '" << DbgName_ << "': " << LastSystemErrorText(); + ythrow yexception() << "Can't create file mapping of '" << DbgName_ << "': " << LastSystemErrorText(); } } else { Mapping_ = MAP_FAILED; @@ -144,7 +144,7 @@ public: PtrStart_ = mmap((caddr_t) nullptr, Length_, ModeToMmapProt(Mode_), ModeToMmapFlags(Mode_), File_.GetHandle(), 0); if ((MAP_FAILED == PtrStart_) && Length_) { - ythrow yexception() << "Can't map " << (unsigned long)Length_ << " bytes of file '" << DbgName_ << "' at offset 0: " << LastSystemErrorText(); + ythrow yexception() << "Can't map " << (unsigned long)Length_ << " bytes of file '" << DbgName_ << "' at offset 0: " << LastSystemErrorText(); } } else { PtrStart_ = nullptr; @@ -152,58 +152,58 @@ public: #endif } - void CheckFile() const { + void CheckFile() const { if (!File_.IsOpen()) { - ythrow yexception() << "TMemoryMap: FILE '" << DbgName_ << "' is not open, " << LastSystemErrorText(); + ythrow yexception() << "TMemoryMap: FILE '" << DbgName_ << "' is not open, " << LastSystemErrorText(); } if (Length_ < 0) { - ythrow yexception() << "'" << DbgName_ << "' is not a regular file"; + ythrow yexception() << "'" << DbgName_ << "' is not a regular file"; } } inline TImpl(FILE* f, EOpenMode om, TString dbgName) : File_(Duplicate(f)) - , DbgName_(std::move(dbgName)) + , DbgName_(std::move(dbgName)) , Length_(File_.GetLength()) , Mode_(om) { - CheckFile(); - CreateMapping(); + CheckFile(); + CreateMapping(); } inline TImpl(const TString& name, EOpenMode om) : File_(name, (om & oRdWr) ? OpenExisting | RdWr : OpenExisting | RdOnly) - , DbgName_(name) + , DbgName_(name) , Length_(File_.GetLength()) , Mode_(om) { - CheckFile(); - CreateMapping(); + CheckFile(); + CreateMapping(); } inline TImpl(const TString& name, i64 length, EOpenMode om) : File_(name, (om & oRdWr) ? OpenExisting | RdWr : OpenExisting | RdOnly) - , DbgName_(name) + , DbgName_(name) , Length_(length) , Mode_(om) { - CheckFile(); + CheckFile(); if (File_.GetLength() < Length_) { File_.Resize(Length_); } - CreateMapping(); + CreateMapping(); } inline TImpl(const TFile& file, EOpenMode om, TString dbgName) : File_(file) - , DbgName_(File_.GetName() ? File_.GetName() : std::move(dbgName)) + , DbgName_(File_.GetName() ? File_.GetName() : std::move(dbgName)) , Length_(File_.GetLength()) , Mode_(om) { - CheckFile(); - CreateMapping(); + CheckFile(); + CreateMapping(); } inline bool IsOpen() const noexcept { @@ -218,15 +218,15 @@ public: return (Mode_ & oRdWr || Mode_ & oCopyOnWr); } - inline TMapResult Map(i64 offset, size_t size) { + inline TMapResult Map(i64 offset, size_t size) { assert(File_.IsOpen()); if (offset > Length_) { - ythrow yexception() << "Can't map something at offset " << offset << " of '" << DbgName_ << "' with length " << Length_; + ythrow yexception() << "Can't map something at offset " << offset << " of '" << DbgName_ << "' with length " << Length_; } if (offset + (i64)size > Length_) { - ythrow yexception() << "Can't map " << (unsigned long)size << " bytes at offset " << offset << " of '" << DbgName_ << "' with length " << Length_; + ythrow yexception() << "Can't map " << (unsigned long)size << " bytes at offset " << offset << " of '" << DbgName_ << "' with length " << Length_; } TMapResult result; @@ -258,7 +258,7 @@ public: if (result.Ptr != nullptr || size == 0) { // allow map of size 0 result.Size = size; } else { - ythrow yexception() << "Can't map " << (unsigned long)size << " bytes at offset " << offset << " of '" << DbgName_ << "': " << LastSystemErrorText(); + ythrow yexception() << "Can't map " << (unsigned long)size << " bytes at offset " << offset << " of '" << DbgName_ << "': " << LastSystemErrorText(); } NSan::Unpoison(result.Ptr, result.Size); if (Mode_ & oPrecharge) { @@ -326,13 +326,13 @@ public: } inline TString GetDbgName() const { - return DbgName_; - } - - inline EOpenMode GetMode() const noexcept { - return Mode_; - } - + return DbgName_; + } + + inline EOpenMode GetMode() const noexcept { + return Mode_; + } + private: TFile File_; TString DbgName_; // This string is never used to actually open a file, only in exceptions @@ -362,29 +362,29 @@ TMemoryMap::TMemoryMap(const TString& name, i64 length, EOpenMode om) } TMemoryMap::TMemoryMap(FILE* f, TString dbgName) - : Impl_(new TImpl(f, EOpenModeFlag::oRdOnly, std::move(dbgName))) + : Impl_(new TImpl(f, EOpenModeFlag::oRdOnly, std::move(dbgName))) { } TMemoryMap::TMemoryMap(FILE* f, EOpenMode om, TString dbgName) - : Impl_(new TImpl(f, om, std::move(dbgName))) + : Impl_(new TImpl(f, om, std::move(dbgName))) { } TMemoryMap::TMemoryMap(const TFile& file, TString dbgName) - : Impl_(new TImpl(file, EOpenModeFlag::oRdOnly, std::move(dbgName))) + : Impl_(new TImpl(file, EOpenModeFlag::oRdOnly, std::move(dbgName))) { } TMemoryMap::TMemoryMap(const TFile& file, EOpenMode om, TString dbgName) - : Impl_(new TImpl(file, om, std::move(dbgName))) + : Impl_(new TImpl(file, om, std::move(dbgName))) { } TMemoryMap::~TMemoryMap() = default; -TMemoryMap::TMapResult TMemoryMap::Map(i64 offset, size_t size) { - return Impl_->Map(offset, size); +TMemoryMap::TMapResult TMemoryMap::Map(i64 offset, size_t size) { + return Impl_->Map(offset, size); } bool TMemoryMap::Unmap(void* ptr, size_t size) { @@ -395,18 +395,18 @@ bool TMemoryMap::Unmap(TMapResult region) { return Unmap(region.Ptr, region.Size); } -void TMemoryMap::ResizeAndReset(i64 size) { - EOpenMode om = Impl_->GetMode(); - TFile file = GetFile(); - file.Resize(size); - Impl_.Reset(new TImpl(file, om, Impl_->GetDbgName())); -} - -TMemoryMap::TMapResult TMemoryMap::ResizeAndRemap(i64 offset, size_t size) { - ResizeAndReset(offset + (i64)size); - return Map(offset, size); -} - +void TMemoryMap::ResizeAndReset(i64 size) { + EOpenMode om = Impl_->GetMode(); + TFile file = GetFile(); + file.Resize(size); + Impl_.Reset(new TImpl(file, om, Impl_->GetDbgName())); +} + +TMemoryMap::TMapResult TMemoryMap::ResizeAndRemap(i64 offset, size_t size) { + ResizeAndReset(offset + (i64)size); + return Map(offset, size); +} + void TMemoryMap::SetSequential() { Impl_->SetSequential(); } @@ -460,12 +460,12 @@ TFileMap::TFileMap(const TString& name, i64 length, EOpenMode om) } TFileMap::TFileMap(FILE* f, EOpenMode om, TString dbgName) - : Map_(f, om, dbgName) + : Map_(f, om, dbgName) { } TFileMap::TFileMap(const TFile& file, EOpenMode om, TString dbgName) - : Map_(file, om, dbgName) + : Map_(file, om, dbgName) { } @@ -491,19 +491,19 @@ void TFileMap::Flush(void* ptr, size_t size, bool sync) { #endif } -TFileMap::TMapResult TFileMap::Map(i64 offset, size_t size) { +TFileMap::TMapResult TFileMap::Map(i64 offset, size_t size) { + Unmap(); + Region_ = Map_.Map(offset, size); + return Region_; +} + +TFileMap::TMapResult TFileMap::ResizeAndRemap(i64 offset, size_t size) { + // explicit Unmap() is required because in oNotGreedy mode the Map_ object doesn't own the mapped area Unmap(); - Region_ = Map_.Map(offset, size); - return Region_; + Region_ = Map_.ResizeAndRemap(offset, size); + return Region_; } -TFileMap::TMapResult TFileMap::ResizeAndRemap(i64 offset, size_t size) { - // explicit Unmap() is required because in oNotGreedy mode the Map_ object doesn't own the mapped area - Unmap(); - Region_ = Map_.ResizeAndRemap(offset, size); - return Region_; -} - void TFileMap::Unmap() { if (!Region_.IsMapped()) { return; @@ -518,7 +518,7 @@ void TFileMap::Unmap() { TFileMap::~TFileMap() { try { - // explicit Unmap() is required because in oNotGreedy mode the Map_ object doesn't own the mapped area + // explicit Unmap() is required because in oNotGreedy mode the Map_ object doesn't own the mapped area Unmap(); } catch (...) { // ¯\_(ツ)_/¯ diff --git a/util/system/filemap.h b/util/system/filemap.h index 31eac6de472..11be64bff47 100644 --- a/util/system/filemap.h +++ b/util/system/filemap.h @@ -80,12 +80,12 @@ public: ~TMemoryMap(); - TMapResult Map(i64 offset, size_t size); + TMapResult Map(i64 offset, size_t size); bool Unmap(TMapResult region); - void ResizeAndReset(i64 size); - TMapResult ResizeAndRemap(i64 offset, size_t size); - + void ResizeAndReset(i64 size); + TMapResult ResizeAndRemap(i64 offset, size_t size); + i64 Length() const noexcept; bool IsOpen() const noexcept; bool IsWritable() const noexcept; @@ -118,8 +118,8 @@ public: ~TFileMap(); - TMapResult Map(i64 offset, size_t size); - TMapResult ResizeAndRemap(i64 offset, size_t size); + TMapResult Map(i64 offset, size_t size); + TMapResult ResizeAndRemap(i64 offset, size_t size); void Unmap(); void Flush(void* ptr, size_t size) { diff --git a/util/system/filemap_ut.cpp b/util/system/filemap_ut.cpp index c796562f267..73f109dc880 100644 --- a/util/system/filemap_ut.cpp +++ b/util/system/filemap_ut.cpp @@ -6,11 +6,11 @@ #include "filemap.h" -#include <util/system/fs.h> - -#include <cstring> -#include <cstdio> - +#include <util/system/fs.h> + +#include <cstring> +#include <cstdio> + Y_UNIT_TEST_SUITE(TFileMapTest) { static const char* FileName_("./mappped_file"); @@ -32,9 +32,9 @@ Y_UNIT_TEST_SUITE(TFileMapTest) { } mappedFile.Flush(); - TFileMap::TMapResult mapResult = mappedFile.Map(2, 2); - UNIT_ASSERT(mapResult.MappedSize() == 2); - UNIT_ASSERT(mapResult.MappedData() == mappedFile.Ptr()); + TFileMap::TMapResult mapResult = mappedFile.Map(2, 2); + UNIT_ASSERT(mapResult.MappedSize() == 2); + UNIT_ASSERT(mapResult.MappedData() == mappedFile.Ptr()); UNIT_ASSERT(mappedFile.MappedSize() == 2); UNIT_ASSERT(static_cast<char*>(mappedFile.Ptr())[0] == 'd' && static_cast<char*>(mappedFile.Ptr())[1] == 'e'); @@ -48,7 +48,7 @@ Y_UNIT_TEST_SUITE(TFileMapTest) { UNIT_ASSERT(static_cast<char*>(mappedFile2.Ptr())[0] == data[0] + 1); fclose(f); } - NFs::Remove(FileName_); + NFs::Remove(FileName_); } Y_UNIT_TEST(TestFileMap) { @@ -60,26 +60,26 @@ Y_UNIT_TEST_SUITE(TFileMapTest) { } Y_UNIT_TEST(TestFileRemap) { - const char data1[] = "01234"; - const char data2[] = "abcdefg"; + const char data1[] = "01234"; + const char data2[] = "abcdefg"; const char data3[] = "COPY"; - const char dataFinal[] = "012abcdefg"; - const size_t data2Shift = 3; - - TFile file(FileName_, CreateAlways | WrOnly); - file.Write(static_cast<const void*>(data1), sizeof(data1)); - file.Close(); - - { - TFileMap mappedFile(FileName_, TMemoryMapCommon::oRdWr); - mappedFile.Map(0, mappedFile.Length()); + const char dataFinal[] = "012abcdefg"; + const size_t data2Shift = 3; + + TFile file(FileName_, CreateAlways | WrOnly); + file.Write(static_cast<const void*>(data1), sizeof(data1)); + file.Close(); + + { + TFileMap mappedFile(FileName_, TMemoryMapCommon::oRdWr); + mappedFile.Map(0, mappedFile.Length()); UNIT_ASSERT(mappedFile.MappedSize() == sizeof(data1) && mappedFile.Length() == sizeof(data1)); - - mappedFile.ResizeAndRemap(data2Shift, sizeof(data2)); - memcpy(mappedFile.Ptr(), data2, sizeof(data2)); - } - + + mappedFile.ResizeAndRemap(data2Shift, sizeof(data2)); + memcpy(mappedFile.Ptr(), data2, sizeof(data2)); + } + { TFileMap mappedFile(FileName_, TMemoryMapCommon::oCopyOnWr); mappedFile.Map(0, mappedFile.Length()); @@ -94,38 +94,38 @@ Y_UNIT_TEST_SUITE(TFileMapTest) { UNIT_ASSERT(data[3] == 'Y'); } - TFile resFile(FileName_, RdOnly); - UNIT_ASSERT(resFile.GetLength() == sizeof(dataFinal)); - char buf[sizeof(dataFinal)]; - resFile.Read(buf, sizeof(dataFinal)); - UNIT_ASSERT(0 == memcmp(buf, dataFinal, sizeof(dataFinal))); - resFile.Close(); - - NFs::Remove(FileName_); - } - + TFile resFile(FileName_, RdOnly); + UNIT_ASSERT(resFile.GetLength() == sizeof(dataFinal)); + char buf[sizeof(dataFinal)]; + resFile.Read(buf, sizeof(dataFinal)); + UNIT_ASSERT(0 == memcmp(buf, dataFinal, sizeof(dataFinal))); + resFile.Close(); + + NFs::Remove(FileName_); + } + Y_UNIT_TEST(TestFileMapDbgName) { - // This test checks that dbgName passed to the TFileMap constructor is saved inside the object and appears - // in subsequent error messages. - const char* const dbgName = "THIS_IS_A_TEST"; - FILE* f = fopen(FileName_, "w+"); - UNIT_ASSERT(f); - { - TFileMap mappedFile(f, TFileMap::oRdWr, dbgName); - bool gotException = false; - try { - // trying to map an empty file to force an exception and check the message - mappedFile.Map(0, 1000); - } catch (const yexception& e) { - gotException = true; - UNIT_ASSERT_STRING_CONTAINS(e.what(), dbgName); - } - UNIT_ASSERT(gotException); - } - fclose(f); - NFs::Remove(FileName_); - } - + // This test checks that dbgName passed to the TFileMap constructor is saved inside the object and appears + // in subsequent error messages. + const char* const dbgName = "THIS_IS_A_TEST"; + FILE* f = fopen(FileName_, "w+"); + UNIT_ASSERT(f); + { + TFileMap mappedFile(f, TFileMap::oRdWr, dbgName); + bool gotException = false; + try { + // trying to map an empty file to force an exception and check the message + mappedFile.Map(0, 1000); + } catch (const yexception& e) { + gotException = true; + UNIT_ASSERT_STRING_CONTAINS(e.what(), dbgName); + } + UNIT_ASSERT(gotException); + } + fclose(f); + NFs::Remove(FileName_); + } + #if defined(_asan_enabled_) || defined(_msan_enabled_) //setrlimit incompatible with asan runtime #elif defined(_cygwin_) @@ -194,7 +194,7 @@ Y_UNIT_TEST_SUITE(TFileMapTest) { } #endif maps.clear(); - NFs::Remove(FileName_); + NFs::Remove(FileName_); } catch (...) { // TODO: RAII'ize all this stuff #if defined(_unix_) @@ -204,7 +204,7 @@ Y_UNIT_TEST_SUITE(TFileMapTest) { throw TSystemError() << "Cannot restore rlimit for virtual memory"; } #endif - NFs::Remove(FileName_); + NFs::Remove(FileName_); throw; } @@ -265,7 +265,7 @@ Y_UNIT_TEST_SUITE(TFileMapTest) { } UNIT_ASSERT(caught); } - NFs::Remove(FileName_); + NFs::Remove(FileName_); } Y_UNIT_TEST(TestMappedArray) { @@ -315,7 +315,7 @@ Y_UNIT_TEST_SUITE(TFileMapTest) { TString text = exc.what(); // exception should contain failed file name UNIT_ASSERT(text.find(FileName_) != TString::npos); } - NFs::Remove(FileName_); + NFs::Remove(FileName_); } Y_UNIT_TEST(TestMemoryMapIsWritable) { @@ -330,7 +330,7 @@ Y_UNIT_TEST_SUITE(TFileMapTest) { TMemoryMap mappedMem(FileName_, TMemoryMap::oRdWr); UNIT_ASSERT(mappedMem.IsWritable()); } - NFs::Remove(FileName_); + NFs::Remove(FileName_); } Y_UNIT_TEST(TestFileMapIsWritable) { @@ -354,6 +354,6 @@ Y_UNIT_TEST_SUITE(TFileMapTest) { TFileMap fileMap(FileName_, TFileMap::oRdWr); UNIT_ASSERT(fileMap.IsWritable()); } - NFs::Remove(FileName_); + NFs::Remove(FileName_); } }; diff --git a/util/system/mincore.cpp b/util/system/mincore.cpp index 7dfb241c86b..8cbae72586a 100644 --- a/util/system/mincore.cpp +++ b/util/system/mincore.cpp @@ -1,35 +1,35 @@ -#include "align.h" -#include "compiler.h" -#include "info.h" -#include "mincore.h" - -#include <util/generic/yexception.h> - -#include <cstring> - -#if defined(_unix_) +#include "align.h" +#include "compiler.h" +#include "info.h" +#include "mincore.h" + +#include <util/generic/yexception.h> + +#include <cstring> + +#if defined(_unix_) #include <sys/unistd.h> #include <sys/mman.h> #if defined(_android_) #include <sys/syscall.h> #endif -#endif - -void InCoreMemory(const void* addr, size_t len, unsigned char* vec, size_t vecLen) { -#if defined(_linux_) - const size_t pageSize = NSystemInfo::GetPageSize(); - void* maddr = const_cast<void*>(AlignDown(addr, pageSize)); - len = AlignUp(len, pageSize); - if (vecLen * pageSize < len) { - ythrow yexception() << "vector argument for mincore is too small: " << vecLen * pageSize << " < " << len; - } - if (::mincore(maddr, len, vec)) { - ythrow yexception() << LastSystemErrorText(); - } -#else - // pessimistic assumption: nothing is in core - Y_UNUSED(addr); - Y_UNUSED(len); - ::memset(vec, 0, vecLen); -#endif -} +#endif + +void InCoreMemory(const void* addr, size_t len, unsigned char* vec, size_t vecLen) { +#if defined(_linux_) + const size_t pageSize = NSystemInfo::GetPageSize(); + void* maddr = const_cast<void*>(AlignDown(addr, pageSize)); + len = AlignUp(len, pageSize); + if (vecLen * pageSize < len) { + ythrow yexception() << "vector argument for mincore is too small: " << vecLen * pageSize << " < " << len; + } + if (::mincore(maddr, len, vec)) { + ythrow yexception() << LastSystemErrorText(); + } +#else + // pessimistic assumption: nothing is in core + Y_UNUSED(addr); + Y_UNUSED(len); + ::memset(vec, 0, vecLen); +#endif +} diff --git a/util/system/mincore.h b/util/system/mincore.h index 1fc3f7d69ce..0f5d8b78c7d 100644 --- a/util/system/mincore.h +++ b/util/system/mincore.h @@ -1,38 +1,38 @@ -#pragma once - -#include "defaults.h" -/** - * Fills a vector that indicates whether pages of the calling process's virtual memory are resident in RAM. Each byte - * in the vector contains the status of a single page. The page size can be obtained via the NSystemInfo::GetPageSize() - * function. Use the IsPageInCore function to interpret the page status byte. - * - * Can be overly pessimistic: - * - Assumes nothing is in RAM on platforms other than Linux - * - Recent Linux kernels (4.21 and some backports) may return zeroes if the process doesn't have writing permissions - * for the given file. See CVE-2019-5489. - * - * @param[in] addr starting address of the memory range to be examined - * @param[in] len length (bytes) of the memory range to be examined - * @param[out] vec vector of bytes to store statuses of memory pages - * @param[in] vecLen length (bytes) of the vec, should be large enough to hold the requested pages count - * @throws yexception if there was a system error or if the vecLen is too small - * - * @note this is only a snapshot, results may be stale by the time they're used - * @see man 2 mincore - */ -void InCoreMemory(const void* addr, size_t len, unsigned char* vec, size_t vecLen); - -/** - * Takes as an argument an element of the vector previously filled by InCoreMemory. - * - * @param[in] byte corresponding to the status of a single page - * - * @returns true if this page was resident in memory at the time out the InCoreMemory execution - */ -inline bool IsPageInCore(unsigned char s) { - /* From mincore(2): On return, the least significant bit of each byte will be set if the corresponding page is - * currently resident in memory, and be clear otherwise. (The settings of the other bits in each byte are - * undefined; these bits are reserved for possible later use.) - */ - return s & 1; -} +#pragma once + +#include "defaults.h" +/** + * Fills a vector that indicates whether pages of the calling process's virtual memory are resident in RAM. Each byte + * in the vector contains the status of a single page. The page size can be obtained via the NSystemInfo::GetPageSize() + * function. Use the IsPageInCore function to interpret the page status byte. + * + * Can be overly pessimistic: + * - Assumes nothing is in RAM on platforms other than Linux + * - Recent Linux kernels (4.21 and some backports) may return zeroes if the process doesn't have writing permissions + * for the given file. See CVE-2019-5489. + * + * @param[in] addr starting address of the memory range to be examined + * @param[in] len length (bytes) of the memory range to be examined + * @param[out] vec vector of bytes to store statuses of memory pages + * @param[in] vecLen length (bytes) of the vec, should be large enough to hold the requested pages count + * @throws yexception if there was a system error or if the vecLen is too small + * + * @note this is only a snapshot, results may be stale by the time they're used + * @see man 2 mincore + */ +void InCoreMemory(const void* addr, size_t len, unsigned char* vec, size_t vecLen); + +/** + * Takes as an argument an element of the vector previously filled by InCoreMemory. + * + * @param[in] byte corresponding to the status of a single page + * + * @returns true if this page was resident in memory at the time out the InCoreMemory execution + */ +inline bool IsPageInCore(unsigned char s) { + /* From mincore(2): On return, the least significant bit of each byte will be set if the corresponding page is + * currently resident in memory, and be clear otherwise. (The settings of the other bits in each byte are + * undefined; these bits are reserved for possible later use.) + */ + return s & 1; +} diff --git a/util/system/mincore_ut.cpp b/util/system/mincore_ut.cpp index 1a7afcc6a59..fc46cb16329 100644 --- a/util/system/mincore_ut.cpp +++ b/util/system/mincore_ut.cpp @@ -1,47 +1,47 @@ #include <library/cpp/testing/unittest/registar.h> - -#ifdef _unix_ + +#ifdef _unix_ #include <sys/resource.h> -#endif - -#include "filemap.h" -#include "info.h" -#include "mincore.h" -#include "mlock.h" -#include "tempfile.h" - -#include <util/generic/size_literals.h> -#include <util/system/fs.h> - -#include <cstring> -#include <cstdio> - -Y_UNIT_TEST_SUITE(MincoreSuite) { - static const char* FileName_("./mappped_file"); - - Y_UNIT_TEST(TestLockAndInCore) { - TVector<char> content(2_MB); - - TTempFile cleanup(FileName_); - TFile file(FileName_, CreateAlways | WrOnly); - file.Write(content.data(), content.size()); - file.Close(); - - TFileMap mappedFile(FileName_, TMemoryMapCommon::oRdWr); - mappedFile.Map(0, mappedFile.Length()); - UNIT_ASSERT_EQUAL(mappedFile.MappedSize(), content.size()); - UNIT_ASSERT_EQUAL(mappedFile.Length(), static_cast<i64>(content.size())); - - LockMemory(mappedFile.Ptr(), mappedFile.Length()); - - TVector<unsigned char> incore(mappedFile.Length() / NSystemInfo::GetPageSize()); - InCoreMemory(mappedFile.Ptr(), mappedFile.Length(), incore.data(), incore.size()); - - // compile and run on all platforms, but assume non-zero results only on Linux -#if defined(_linux_) - for (const auto& flag : incore) { - UNIT_ASSERT(IsPageInCore(flag)); - } -#endif - } -} +#endif + +#include "filemap.h" +#include "info.h" +#include "mincore.h" +#include "mlock.h" +#include "tempfile.h" + +#include <util/generic/size_literals.h> +#include <util/system/fs.h> + +#include <cstring> +#include <cstdio> + +Y_UNIT_TEST_SUITE(MincoreSuite) { + static const char* FileName_("./mappped_file"); + + Y_UNIT_TEST(TestLockAndInCore) { + TVector<char> content(2_MB); + + TTempFile cleanup(FileName_); + TFile file(FileName_, CreateAlways | WrOnly); + file.Write(content.data(), content.size()); + file.Close(); + + TFileMap mappedFile(FileName_, TMemoryMapCommon::oRdWr); + mappedFile.Map(0, mappedFile.Length()); + UNIT_ASSERT_EQUAL(mappedFile.MappedSize(), content.size()); + UNIT_ASSERT_EQUAL(mappedFile.Length(), static_cast<i64>(content.size())); + + LockMemory(mappedFile.Ptr(), mappedFile.Length()); + + TVector<unsigned char> incore(mappedFile.Length() / NSystemInfo::GetPageSize()); + InCoreMemory(mappedFile.Ptr(), mappedFile.Length(), incore.data(), incore.size()); + + // compile and run on all platforms, but assume non-zero results only on Linux +#if defined(_linux_) + for (const auto& flag : incore) { + UNIT_ASSERT(IsPageInCore(flag)); + } +#endif + } +} diff --git a/util/system/unaligned_mem.h b/util/system/unaligned_mem.h index abcdde9fd6e..4b84686f2f2 100644 --- a/util/system/unaligned_mem.h +++ b/util/system/unaligned_mem.h @@ -6,11 +6,11 @@ #include <string.h> #include <type_traits> -// The following code used to have smart tricks assuming that unaligned reads and writes are OK on x86. This assumption -// is wrong because compiler may emit alignment-sensitive x86 instructions e.g. movaps. See IGNIETFERRO-735. - +// The following code used to have smart tricks assuming that unaligned reads and writes are OK on x86. This assumption +// is wrong because compiler may emit alignment-sensitive x86 instructions e.g. movaps. See IGNIETFERRO-735. + template <class T> -inline T ReadUnaligned(const void* from) noexcept { +inline T ReadUnaligned(const void* from) noexcept { T ret; memcpy(&ret, from, sizeof(T)); return ret; diff --git a/util/system/unaligned_mem_ut.cpp b/util/system/unaligned_mem_ut.cpp index 3c575d4f699..9de3f3e9311 100644 --- a/util/system/unaligned_mem_ut.cpp +++ b/util/system/unaligned_mem_ut.cpp @@ -3,94 +3,94 @@ #include <library/cpp/testing/benchmark/bench.h> #include <library/cpp/testing/unittest/registar.h> -#include <util/system/compiler.h> - -#ifdef Y_HAVE_INT128 -namespace { - struct TUInt128 { - bool operator==(const TUInt128& other) const { - return x == other.x; - } - - ui64 Low() const { - return (ui64)x; - } - - ui64 High() const { - return (ui64)(x >> 64); - } - - static TUInt128 Max() { +#include <util/system/compiler.h> + +#ifdef Y_HAVE_INT128 +namespace { + struct TUInt128 { + bool operator==(const TUInt128& other) const { + return x == other.x; + } + + ui64 Low() const { + return (ui64)x; + } + + ui64 High() const { + return (ui64)(x >> 64); + } + + static TUInt128 Max() { return {~(__uint128_t)0}; - } - - __uint128_t x; - }; -} -#endif - + } + + __uint128_t x; + }; +} +#endif + Y_UNIT_TEST_SUITE(UnalignedMem) { Y_UNIT_TEST(TestReadWrite) { - alignas(ui64) char buf[100]; + alignas(ui64) char buf[100]; WriteUnaligned<ui16>(buf + 1, (ui16)1); WriteUnaligned<ui32>(buf + 1 + 2, (ui32)2); WriteUnaligned<ui64>(buf + 1 + 2 + 4, (ui64)3); - UNIT_ASSERT_VALUES_EQUAL(ReadUnaligned<ui16>(buf + 1), 1); - UNIT_ASSERT_VALUES_EQUAL(ReadUnaligned<ui32>(buf + 1 + 2), 2); - UNIT_ASSERT_VALUES_EQUAL(ReadUnaligned<ui64>(buf + 1 + 2 + 4), 3); + UNIT_ASSERT_VALUES_EQUAL(ReadUnaligned<ui16>(buf + 1), 1); + UNIT_ASSERT_VALUES_EQUAL(ReadUnaligned<ui32>(buf + 1 + 2), 2); + UNIT_ASSERT_VALUES_EQUAL(ReadUnaligned<ui64>(buf + 1 + 2 + 4), 3); } - + Y_UNIT_TEST(TestReadWriteRuntime) { - // Unlike the test above, this test avoids compile-time execution by a smart compiler. - // It is required to catch the SIGSEGV in case compiler emits an alignment-sensitive instruction. - - alignas(ui64) static char buf[100] = {0}; // static is required for Clobber to work - + // Unlike the test above, this test avoids compile-time execution by a smart compiler. + // It is required to catch the SIGSEGV in case compiler emits an alignment-sensitive instruction. + + alignas(ui64) static char buf[100] = {0}; // static is required for Clobber to work + WriteUnaligned<ui16>(buf + 1, (ui16)1); WriteUnaligned<ui32>(buf + 1 + 2, (ui32)2); WriteUnaligned<ui64>(buf + 1 + 2 + 4, (ui64)3); - NBench::Clobber(); - - auto val1 = ReadUnaligned<ui16>(buf + 1); - auto val2 = ReadUnaligned<ui32>(buf + 1 + 2); - auto val3 = ReadUnaligned<ui64>(buf + 1 + 2 + 4); - - Y_DO_NOT_OPTIMIZE_AWAY(&val1); - Y_DO_NOT_OPTIMIZE_AWAY(&val2); - Y_DO_NOT_OPTIMIZE_AWAY(&val3); - Y_DO_NOT_OPTIMIZE_AWAY(val1); - Y_DO_NOT_OPTIMIZE_AWAY(val2); - Y_DO_NOT_OPTIMIZE_AWAY(val3); - - UNIT_ASSERT_VALUES_EQUAL(val1, 1); - UNIT_ASSERT_VALUES_EQUAL(val2, 2); - UNIT_ASSERT_VALUES_EQUAL(val3, 3); - } -#ifdef Y_HAVE_INT128 + NBench::Clobber(); + + auto val1 = ReadUnaligned<ui16>(buf + 1); + auto val2 = ReadUnaligned<ui32>(buf + 1 + 2); + auto val3 = ReadUnaligned<ui64>(buf + 1 + 2 + 4); + + Y_DO_NOT_OPTIMIZE_AWAY(&val1); + Y_DO_NOT_OPTIMIZE_AWAY(&val2); + Y_DO_NOT_OPTIMIZE_AWAY(&val3); + Y_DO_NOT_OPTIMIZE_AWAY(val1); + Y_DO_NOT_OPTIMIZE_AWAY(val2); + Y_DO_NOT_OPTIMIZE_AWAY(val3); + + UNIT_ASSERT_VALUES_EQUAL(val1, 1); + UNIT_ASSERT_VALUES_EQUAL(val2, 2); + UNIT_ASSERT_VALUES_EQUAL(val3, 3); + } +#ifdef Y_HAVE_INT128 Y_UNIT_TEST(TestReadWrite128) { - alignas(TUInt128) char buf[100] = {0}; - + alignas(TUInt128) char buf[100] = {0}; + WriteUnaligned<TUInt128>(buf + 1, TUInt128::Max()); - auto val = ReadUnaligned<TUInt128>(buf + 1); - UNIT_ASSERT(val == TUInt128::Max()); - } + auto val = ReadUnaligned<TUInt128>(buf + 1); + UNIT_ASSERT(val == TUInt128::Max()); + } Y_UNIT_TEST(TestReadWriteRuntime128) { - // Unlike the test above, this test avoids compile-time execution by a smart compiler. - // It is required to catch the SIGSEGV in case compiler emits an alignment-sensitive instruction. - - alignas(TUInt128) static char buf[100] = {0}; // static is required for Clobber to work - + // Unlike the test above, this test avoids compile-time execution by a smart compiler. + // It is required to catch the SIGSEGV in case compiler emits an alignment-sensitive instruction. + + alignas(TUInt128) static char buf[100] = {0}; // static is required for Clobber to work + WriteUnaligned<TUInt128>(buf + 1, TUInt128::Max()); - NBench::Clobber(); - - auto val = ReadUnaligned<TUInt128>(buf + 1); - Y_DO_NOT_OPTIMIZE_AWAY(&val); - Y_DO_NOT_OPTIMIZE_AWAY(val.Low()); - Y_DO_NOT_OPTIMIZE_AWAY(val.High()); - - UNIT_ASSERT(val == TUInt128::Max()); - } -#endif + NBench::Clobber(); + + auto val = ReadUnaligned<TUInt128>(buf + 1); + Y_DO_NOT_OPTIMIZE_AWAY(&val); + Y_DO_NOT_OPTIMIZE_AWAY(val.Low()); + Y_DO_NOT_OPTIMIZE_AWAY(val.High()); + + UNIT_ASSERT(val == TUInt128::Max()); + } +#endif } diff --git a/util/system/ut/ya.make b/util/system/ut/ya.make index 8187e2110be..127e7c261e4 100644 --- a/util/system/ut/ya.make +++ b/util/system/ut/ya.make @@ -19,10 +19,10 @@ IF (OS_DARWIN) TIMEOUT(3600) ENDIF() -PEERDIR( +PEERDIR( library/cpp/testing/benchmark -) - +) + SRCS( system/align_ut.cpp system/atexit_ut.cpp @@ -53,7 +53,7 @@ SRCS( system/info_ut.cpp system/interrupt_signals_ut.cpp system/mem_info_ut.cpp - system/mincore_ut.cpp + system/mincore_ut.cpp system/mutex_ut.cpp system/nice_ut.cpp system/pipe_ut.cpp |