memory_segment_mapped_unittest.cc 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. // Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <util/memory_segment_mapped.h>
  15. #include <gtest/gtest.h>
  16. #include <boost/interprocess/file_mapping.hpp>
  17. #include <boost/scoped_ptr.hpp>
  18. #include <cstdlib>
  19. #include <limits>
  20. #include <stdexcept>
  21. using namespace isc::util;
  22. using boost::scoped_ptr;
  23. namespace {
  24. const char* const mapped_file = TEST_DATA_BUILDDIR "/test.mapped";
  25. const size_t DEFAULT_INITIAL_SIZE = 32 * 1024; // intentionally hardcoded
  26. class MemorySegmentMappedTest : public ::testing::Test {
  27. protected:
  28. MemorySegmentMappedTest() {
  29. resetSegment();
  30. }
  31. ~MemorySegmentMappedTest() {
  32. segment_.reset();
  33. boost::interprocess::file_mapping::remove(mapped_file);
  34. }
  35. // For initialization and for tests after the segment possibly becomes
  36. // broken.
  37. void resetSegment() {
  38. segment_.reset();
  39. boost::interprocess::file_mapping::remove(mapped_file);
  40. segment_.reset(new MemorySegmentMapped(mapped_file, true));
  41. }
  42. scoped_ptr<MemorySegmentMapped> segment_;
  43. };
  44. TEST_F(MemorySegmentMappedTest, createAndModify) {
  45. // We are going to do the same set of basic tests twice; one after creating
  46. // the mapped file, the other by re-opening the existing file in the
  47. // read-write mode.
  48. for (int i = 0; i < 2; ++i) {
  49. // It should have the default size (intentionally hardcoded)
  50. EXPECT_EQ(DEFAULT_INITIAL_SIZE, segment_->getSize());
  51. // By default, nothing is allocated.
  52. EXPECT_TRUE(segment_->allMemoryDeallocated());
  53. void* ptr = segment_->allocate(1024);
  54. EXPECT_NE(static_cast<void*>(0), ptr);
  55. // Now, we have an allocation:
  56. EXPECT_FALSE(segment_->allMemoryDeallocated());
  57. // deallocate it; it shouldn't cause disruption.
  58. segment_->deallocate(ptr, 1024);
  59. EXPECT_TRUE(segment_->allMemoryDeallocated());
  60. // re-open it.
  61. segment_.reset(new MemorySegmentMapped(mapped_file, false));
  62. }
  63. }
  64. TEST_F(MemorySegmentMappedTest, createWithSize) {
  65. boost::interprocess::file_mapping::remove(mapped_file);
  66. // Re-create the mapped file with a non-default initial size, and confirm
  67. // the size is actually the specified one.
  68. segment_.reset(new MemorySegmentMapped(mapped_file, true, 64 * 1024));
  69. EXPECT_NE(DEFAULT_INITIAL_SIZE, 64 * 1024);
  70. EXPECT_EQ(64 * 1024, segment_->getSize());
  71. }
  72. TEST_F(MemorySegmentMappedTest, openFail) {
  73. // The given file is directory
  74. EXPECT_THROW(MemorySegmentMapped("/", true), MemorySegmentOpenError);
  75. // file doesn't exist and directory isn't writable (we assume the root
  76. // directory is not writable for the user running the test).
  77. EXPECT_THROW(MemorySegmentMapped("/test.mapped", true),
  78. MemorySegmentOpenError);
  79. // file doesn't exist and it's read-only (so open-only)
  80. EXPECT_THROW(MemorySegmentMapped(TEST_DATA_BUILDDIR "/nosuchfile.mapped"),
  81. MemorySegmentOpenError);
  82. // Likewise. read-write mode but creation is suppressed.
  83. EXPECT_THROW(MemorySegmentMapped(TEST_DATA_BUILDDIR "/nosuchfile.mapped",
  84. false),
  85. MemorySegmentOpenError);
  86. }
  87. TEST_F(MemorySegmentMappedTest, allocate) {
  88. // Various case of allocation. The simplest cases are covered above.
  89. // (Clearly) exceeding the available size, which should cause growing
  90. // the segment
  91. EXPECT_THROW(segment_->allocate(DEFAULT_INITIAL_SIZE + 1),
  92. MemorySegmentGrown);
  93. // The size should have been doubled.
  94. EXPECT_EQ(DEFAULT_INITIAL_SIZE * 2, segment_->getSize());
  95. // In this case it should now succeed.
  96. void* ptr = segment_->allocate(DEFAULT_INITIAL_SIZE + 1);
  97. EXPECT_NE(static_cast<void*>(0), ptr);
  98. EXPECT_FALSE(segment_->allMemoryDeallocated());
  99. // Same set of checks, but for a larger size.
  100. EXPECT_THROW(segment_->allocate(DEFAULT_INITIAL_SIZE * 10),
  101. MemorySegmentGrown);
  102. // the segment should have grown to the minimum size that could allocate
  103. // the given size of memory.
  104. EXPECT_EQ(DEFAULT_INITIAL_SIZE * 16, segment_->getSize());
  105. // And allocate() should now succeed.
  106. ptr = segment_->allocate(DEFAULT_INITIAL_SIZE * 10);
  107. EXPECT_NE(static_cast<void*>(0), ptr);
  108. // (we'll left the regions created in the file there; the entire file
  109. // will be removed at the end of the test)
  110. }
  111. TEST_F(MemorySegmentMappedTest, badAllocate) {
  112. // Make the mapped file non-writable; managed_mapped_file::grow() will
  113. // fail, resulting in std::bad_alloc
  114. const std::string chmod_cmd = "chmod 444 " + std::string(mapped_file);
  115. std::system(chmod_cmd.c_str());
  116. EXPECT_THROW(segment_->allocate(DEFAULT_INITIAL_SIZE * 2), std::bad_alloc);
  117. }
  118. // XXX: this test can cause too strong side effect (creating a very large
  119. // file), so we disable it by default
  120. TEST_F(MemorySegmentMappedTest, DISABLED_allocateHuge) {
  121. EXPECT_THROW(segment_->allocate(std::numeric_limits<size_t>::max()),
  122. std::bad_alloc);
  123. }
  124. TEST_F(MemorySegmentMappedTest, badDeallocate) {
  125. void* ptr = segment_->allocate(4);
  126. EXPECT_NE(static_cast<void*>(0), ptr);
  127. segment_->deallocate(ptr, 4); // this is okay
  128. // This is duplicate dealloc; should trigger assertion failure.
  129. EXPECT_DEATH_IF_SUPPORTED({segment_->deallocate(ptr, 4);}, "");
  130. resetSegment(); // the segment is possibly broken; reset it.
  131. // Deallocating at an invalid address; this would result in crash (the
  132. // behavior may not be portable enough; if so we should disable it by
  133. // default).
  134. ptr = segment_->allocate(4);
  135. EXPECT_NE(static_cast<void*>(0), ptr);
  136. EXPECT_DEATH_IF_SUPPORTED({
  137. segment_->deallocate(static_cast<char*>(ptr) + 1, 3);
  138. }, "");
  139. resetSegment();
  140. // Invalid size; this implementation doesn't detect such errors.
  141. ptr = segment_->allocate(4);
  142. EXPECT_NE(static_cast<void*>(0), ptr);
  143. segment_->deallocate(ptr, 8);
  144. EXPECT_TRUE(segment_->allMemoryDeallocated());
  145. }
  146. /*
  147. TEST(MemorySegmentLocal, TestNullDeallocate) {
  148. auto_ptr<MemorySegment> segment(new MemorySegmentLocal());
  149. // By default, nothing is allocated.
  150. EXPECT_TRUE(segment->allMemoryDeallocated());
  151. // NULL deallocation is a no-op.
  152. EXPECT_NO_THROW(segment->deallocate(NULL, 1024));
  153. // This should still return true.
  154. EXPECT_TRUE(segment->allMemoryDeallocated());
  155. }
  156. */
  157. }