madv_free_discardable_memory_posix_unittest.cc 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include <fcntl.h>
  5. #include <stdint.h>
  6. #include <sys/mman.h>
  7. #include <memory>
  8. #include "base/bind.h"
  9. #include "base/callback.h"
  10. #include "base/callback_helpers.h"
  11. #include "base/files/scoped_file.h"
  12. #include "base/memory/madv_free_discardable_memory_allocator_posix.h"
  13. #include "base/memory/madv_free_discardable_memory_posix.h"
  14. #include "base/memory/page_size.h"
  15. #include "build/build_config.h"
  16. #include "testing/gtest/include/gtest/gtest.h"
  17. #define SUCCEED_IF_MADV_FREE_UNSUPPORTED() \
  18. do { \
  19. if (GetMadvFreeSupport() != base::MadvFreeSupport::kSupported) { \
  20. SUCCEED() \
  21. << "MADV_FREE is not supported (Linux 4.5+ required), vacuously " \
  22. "passing test"; \
  23. return; \
  24. } \
  25. } while (0)
  26. namespace base {
  27. std::atomic<size_t> allocator_byte_count;
  28. class MadvFreeDiscardableMemoryPosixTester
  29. : public MadvFreeDiscardableMemoryPosix {
  30. public:
  31. MadvFreeDiscardableMemoryPosixTester(size_t size_in_bytes)
  32. : MadvFreeDiscardableMemoryPosix(size_in_bytes, &allocator_byte_count) {}
  33. using MadvFreeDiscardableMemoryPosix::DiscardPage;
  34. using MadvFreeDiscardableMemoryPosix::GetPageCount;
  35. using MadvFreeDiscardableMemoryPosix::IsLockedForTesting;
  36. using MadvFreeDiscardableMemoryPosix::IsValid;
  37. using MadvFreeDiscardableMemoryPosix::SetKeepMemoryForTesting;
  38. };
  39. class MadvFreeDiscardableMemoryTest : public ::testing::Test {
  40. protected:
  41. MadvFreeDiscardableMemoryTest() {}
  42. ~MadvFreeDiscardableMemoryTest() override {}
  43. const size_t kPageSize = base::GetPageSize();
  44. std::unique_ptr<MadvFreeDiscardableMemoryPosixTester>
  45. AllocateLockedDiscardableMemoryPagesForTest(size_t size_in_pages) {
  46. return std::make_unique<MadvFreeDiscardableMemoryPosixTester>(
  47. size_in_pages * kPageSize);
  48. }
  49. };
  50. using MadvFreeDiscardableMemoryDeathTest = MadvFreeDiscardableMemoryTest;
  51. constexpr char kTestPattern[] =
  52. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  53. TEST_F(MadvFreeDiscardableMemoryTest, AllocateAndUse) {
  54. SUCCEED_IF_MADV_FREE_UNSUPPORTED();
  55. std::unique_ptr<MadvFreeDiscardableMemoryPosixTester> mem =
  56. AllocateLockedDiscardableMemoryPagesForTest(1);
  57. mem->SetKeepMemoryForTesting(true);
  58. ASSERT_TRUE(mem->IsValid());
  59. ASSERT_TRUE(mem->IsLockedForTesting());
  60. char buffer[sizeof(kTestPattern)];
  61. // Write test pattern to block
  62. uint8_t* data = mem->data_as<uint8_t>();
  63. memcpy(data, kTestPattern, sizeof(kTestPattern));
  64. // Read test pattern from block
  65. data = mem->data_as<uint8_t>();
  66. memcpy(buffer, data, sizeof(kTestPattern));
  67. EXPECT_EQ(memcmp(kTestPattern, buffer, sizeof(kTestPattern)), 0);
  68. // Memory contents should not change after successful unlock and lock.
  69. mem->Unlock();
  70. ASSERT_TRUE(mem->Lock());
  71. EXPECT_EQ(memcmp(kTestPattern, buffer, sizeof(kTestPattern)), 0);
  72. }
  73. TEST_F(MadvFreeDiscardableMemoryTest, LockAndUnlock) {
  74. SUCCEED_IF_MADV_FREE_UNSUPPORTED();
  75. const size_t kPageCount = 10;
  76. std::unique_ptr<MadvFreeDiscardableMemoryPosixTester> mem =
  77. AllocateLockedDiscardableMemoryPagesForTest(kPageCount);
  78. ASSERT_TRUE(mem->IsValid());
  79. ASSERT_TRUE(mem->IsLockedForTesting());
  80. memset(mem->data(), 0xE7, kPageSize * kPageCount);
  81. mem->Unlock();
  82. ASSERT_FALSE(mem->IsLockedForTesting());
  83. bool result = mem->Lock();
  84. // If Lock() succeeded, the memory region should be valid. If Lock() failed,
  85. // the memory region should be invalid.
  86. ASSERT_EQ(result, mem->IsValid());
  87. }
  88. TEST_F(MadvFreeDiscardableMemoryTest, LockShouldFailAfterDiscard) {
  89. SUCCEED_IF_MADV_FREE_UNSUPPORTED();
  90. constexpr size_t kPageCount = 10;
  91. std::unique_ptr<MadvFreeDiscardableMemoryPosixTester> mem =
  92. AllocateLockedDiscardableMemoryPagesForTest(kPageCount);
  93. uint8_t* data = mem->data_as<uint8_t>();
  94. ASSERT_TRUE(mem->IsValid());
  95. ASSERT_TRUE(mem->IsLockedForTesting());
  96. // Modify block data such that at least one page is non-zero.
  97. memset(data, 0xff, kPageSize * kPageCount);
  98. mem->Unlock();
  99. ASSERT_FALSE(mem->IsLockedForTesting());
  100. // Forcefully discard at least one non-zero page.
  101. mem->DiscardPage(5);
  102. // Locking when a page has been discarded should fail.
  103. ASSERT_FALSE(mem->Lock());
  104. // Locking after memory is deallocated should fail.
  105. ASSERT_FALSE(mem->Lock());
  106. // Check that memory has been deallocated.
  107. ASSERT_FALSE(mem->IsValid());
  108. }
  109. } // namespace base