123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613 |
- #include <util/tests/memory_segment_common_unittest.h>
- #include <util/unittests/check_valgrind.h>
- #include <util/tests/interprocess_util.h>
- #include <util/memory_segment_mapped.h>
- #include <exceptions/exceptions.h>
- #include <gtest/gtest.h>
- #include <boost/interprocess/file_mapping.hpp>
- #include <boost/interprocess/mapped_region.hpp>
- #include <boost/scoped_ptr.hpp>
- #include <boost/foreach.hpp>
- #include <stdint.h>
- #include <cstdlib>
- #include <cstring>
- #include <limits>
- #include <stdexcept>
- #include <fstream>
- #include <string>
- #include <vector>
- #include <map>
- #include <sys/stat.h>
- #include <unistd.h>
- #include <stdlib.h>
- using namespace isc::util;
- using boost::scoped_ptr;
- using isc::util::test::parentReadState;
- namespace {
- const MemorySegmentMapped::OpenMode OPEN_FOR_WRITE =
- MemorySegmentMapped::OPEN_FOR_WRITE;
- const MemorySegmentMapped::OpenMode OPEN_OR_CREATE =
- MemorySegmentMapped::OPEN_OR_CREATE;
- const MemorySegmentMapped::OpenMode CREATE_ONLY =
- MemorySegmentMapped::CREATE_ONLY;
- const char* const mapped_file = TEST_DATA_BUILDDIR "/test.mapped";
- const size_t DEFAULT_INITIAL_SIZE = 32 * 1024;
- class PipeHolder {
- public:
- PipeHolder() {
- if (pipe(fds_) == -1) {
- isc_throw(isc::Unexpected, "pipe failed");
- }
- }
- ~PipeHolder() {
- close(fds_[0]);
- close(fds_[1]);
- }
- int getReadFD() const { return (fds_[0]); }
- int getWriteFD() const { return (fds_[1]); }
- private:
- int fds_[2];
- };
- class MemorySegmentMappedTest : public ::testing::Test {
- protected:
- MemorySegmentMappedTest() {
- resetSegment();
- }
- ~MemorySegmentMappedTest() {
- segment_.reset();
- boost::interprocess::file_mapping::remove(mapped_file);
- }
-
-
- void resetSegment() {
- segment_.reset();
- boost::interprocess::file_mapping::remove(mapped_file);
- segment_.reset(new MemorySegmentMapped(mapped_file, OPEN_OR_CREATE));
- }
- scoped_ptr<MemorySegmentMapped> segment_;
- };
- TEST_F(MemorySegmentMappedTest, createAndModify) {
-
-
-
- for (int i = 0; i < 2; ++i) {
-
- EXPECT_EQ(DEFAULT_INITIAL_SIZE, segment_->getSize());
-
- EXPECT_TRUE(segment_->allMemoryDeallocated());
- void* ptr = segment_->allocate(1024);
- EXPECT_NE(static_cast<void*>(NULL), ptr);
-
- EXPECT_FALSE(segment_->allMemoryDeallocated());
-
- segment_->deallocate(ptr, 1024);
- EXPECT_TRUE(segment_->allMemoryDeallocated());
-
-
- segment_.reset();
- segment_.reset(new MemorySegmentMapped(mapped_file, OPEN_FOR_WRITE));
- }
- }
- TEST_F(MemorySegmentMappedTest, createWithSize) {
- boost::interprocess::file_mapping::remove(mapped_file);
-
-
- const size_t new_size = 64 * 1024;
- EXPECT_NE(new_size, segment_->getSize());
- segment_.reset();
- segment_.reset(new MemorySegmentMapped(mapped_file, OPEN_OR_CREATE,
- new_size));
- EXPECT_EQ(new_size, segment_->getSize());
- }
- TEST_F(MemorySegmentMappedTest, createOnly) {
-
- EXPECT_TRUE(segment_->allocate(16));
-
-
-
- segment_.reset();
- segment_.reset(new MemorySegmentMapped(mapped_file, CREATE_ONLY));
- EXPECT_TRUE(segment_->allMemoryDeallocated());
- }
- TEST_F(MemorySegmentMappedTest, openFail) {
-
- EXPECT_THROW(MemorySegmentMapped("/", OPEN_OR_CREATE),
- MemorySegmentOpenError);
-
-
- EXPECT_THROW(MemorySegmentMapped("/random-glkwjer098/test.mapped",
- OPEN_OR_CREATE), MemorySegmentOpenError);
-
-
- EXPECT_THROW(MemorySegmentMapped(TEST_DATA_BUILDDIR "/nosuchfile.mapped"),
- MemorySegmentOpenError);
-
-
- EXPECT_THROW(MemorySegmentMapped(TEST_DATA_BUILDDIR "/nosuchfile.mapped",
- OPEN_FOR_WRITE), MemorySegmentOpenError);
-
-
-
- EXPECT_THROW(MemorySegmentMapped(mapped_file, OPEN_OR_CREATE, 0),
- MemorySegmentOpenError);
-
- EXPECT_THROW(MemorySegmentMapped(
- mapped_file,
- static_cast<MemorySegmentMapped::OpenMode>(
- static_cast<int>(CREATE_ONLY) + 1)),
- isc::InvalidParameter);
-
-
-
- segment_.reset();
- std::ofstream ofs(mapped_file, std::ios::trunc);
- ofs << std::string(1024, 'x');
- ofs.close();
- EXPECT_THROW(MemorySegmentMapped sgmt(mapped_file), MemorySegmentOpenError);
- EXPECT_THROW(MemorySegmentMapped sgmt(mapped_file, OPEN_FOR_WRITE),
- MemorySegmentOpenError);
- EXPECT_THROW(MemorySegmentMapped sgmt(mapped_file, OPEN_OR_CREATE),
- MemorySegmentOpenError);
- }
- TEST_F(MemorySegmentMappedTest, allocate) {
-
-
- EXPECT_TRUE(segment_->allMemoryDeallocated());
-
-
- const size_t prev_size = segment_->getSize();
- EXPECT_THROW(segment_->allocate(prev_size + 1), MemorySegmentGrown);
-
- EXPECT_EQ(prev_size * 2, segment_->getSize());
-
- EXPECT_TRUE(segment_->allMemoryDeallocated());
-
- void* ptr = segment_->allocate(prev_size + 1);
- EXPECT_NE(static_cast<void*>(NULL), ptr);
- EXPECT_FALSE(segment_->allMemoryDeallocated());
-
- EXPECT_THROW(segment_->allocate(prev_size * 10), MemorySegmentGrown);
-
-
- EXPECT_EQ(prev_size * 16, segment_->getSize());
-
- ptr = segment_->allocate(prev_size * 10);
- EXPECT_NE(static_cast<void*>(NULL), ptr);
-
-
- }
- TEST_F(MemorySegmentMappedTest, badAllocate) {
-
-
- const int ret = chmod(mapped_file, 0444);
- ASSERT_EQ(0, ret);
- EXPECT_THROW(segment_->allocate(DEFAULT_INITIAL_SIZE * 2), std::bad_alloc);
- }
- TEST_F(MemorySegmentMappedTest, DISABLED_allocateHuge) {
- EXPECT_THROW(segment_->allocate(std::numeric_limits<size_t>::max()),
- std::bad_alloc);
- }
- TEST_F(MemorySegmentMappedTest, badDeallocate) {
- void* ptr = segment_->allocate(4);
- EXPECT_NE(static_cast<void*>(NULL), ptr);
- segment_->deallocate(ptr, 4);
-
- if (!isc::util::unittests::runningOnValgrind()) {
- EXPECT_DEATH_IF_SUPPORTED({segment_->deallocate(ptr, 4);}, "");
- resetSegment();
- }
-
-
-
- if (!isc::util::unittests::runningOnValgrind()) {
- ptr = segment_->allocate(4);
- EXPECT_NE(static_cast<void*>(NULL), ptr);
- EXPECT_DEATH_IF_SUPPORTED({
- segment_->deallocate(static_cast<char*>(ptr) + 1, 3);
- }, "");
- resetSegment();
- }
-
- ptr = segment_->allocate(4);
- EXPECT_NE(static_cast<void*>(NULL), ptr);
- segment_->deallocate(ptr, 8);
- EXPECT_TRUE(segment_->allMemoryDeallocated());
- }
- void
- checkNamedData(const std::string& name, const std::vector<uint8_t>& data,
- MemorySegment& sgmt, bool delete_after_check = false)
- {
- void* dp = sgmt.getNamedAddress(name.c_str());
- ASSERT_TRUE(dp);
- EXPECT_EQ(0, std::memcmp(dp, &data[0], data.size()));
- if (delete_after_check) {
- sgmt.deallocate(dp, data.size());
- sgmt.clearNamedAddress(name.c_str());
- }
- }
- TEST_F(MemorySegmentMappedTest, namedAddress) {
-
- isc::util::test::checkSegmentNamedAddress(*segment_, false);
-
- void* ptr16 = segment_->allocate(sizeof(uint16_t));
- const uint16_t test_val16 = 42000;
- *static_cast<uint16_t*>(ptr16) = test_val16;
- EXPECT_FALSE(segment_->setNamedAddress("test address", ptr16));
- segment_.reset();
- segment_.reset(new MemorySegmentMapped(mapped_file));
- EXPECT_NE(static_cast<void*>(NULL),
- segment_->getNamedAddress("test address"));
- EXPECT_EQ(test_val16, *static_cast<const uint16_t*>(
- segment_->getNamedAddress("test address")));
-
-
-
- segment_.reset();
- boost::interprocess::file_mapping::remove(mapped_file);
- segment_.reset(new MemorySegmentMapped(mapped_file, OPEN_OR_CREATE, 1024));
- const std::string long_name(1025, 'x');
-
- EXPECT_TRUE(segment_->setNamedAddress(long_name.c_str(), NULL));
- EXPECT_EQ(static_cast<void*>(NULL),
- segment_->getNamedAddress(long_name.c_str()));
-
-
- segment_.reset();
- boost::interprocess::file_mapping::remove(mapped_file);
- segment_.reset(new MemorySegmentMapped(mapped_file, OPEN_OR_CREATE));
- typedef std::map<std::string, std::vector<uint8_t> > TestData;
- TestData data_list;
- data_list["data1"] =
- std::vector<uint8_t>(80);
- data_list["data2"] =
- std::vector<uint8_t>(5000);
- data_list["data3"] =
- std::vector<uint8_t>(65535);
- bool grown = false;
-
- for (TestData::iterator it = data_list.begin(); it != data_list.end();
- ++it)
- {
- std::vector<uint8_t>& data = it->second;
- for (int i = 0; i < data.size(); ++i) {
- data[i] = i;
- }
- void *dp = NULL;
- while (!dp) {
- try {
- dp = segment_->allocate(data.size());
- std::memcpy(dp, &data[0], data.size());
- segment_->setNamedAddress(it->first.c_str(), dp);
- } catch (const MemorySegmentGrown&) {
- grown = true;
- }
- }
- }
-
- EXPECT_TRUE(grown);
-
- for (TestData::iterator it = data_list.begin(); it != data_list.end();
- ++it)
- {
- checkNamedData(it->first, it->second, *segment_);
- }
-
-
-
- const char* const names[] = { "data3", "data2", "data1", NULL };
- for (int i = 0; names[i]; ++i) {
- checkNamedData(names[i], data_list[names[i]], *segment_, true);
- segment_->shrinkToFit();
- }
- }
- TEST_F(MemorySegmentMappedTest, multiProcess) {
-
- if (isc::util::unittests::runningOnValgrind()) {
- return;
- }
-
- void* ptr = segment_->allocate(sizeof(uint32_t));
- *static_cast<uint32_t*>(ptr) = 424242;
- segment_->setNamedAddress("test address", ptr);
-
-
-
- segment_.reset();
-
- PipeHolder pipe_to_child;
- PipeHolder pipe_to_parent;
- const pid_t child_pid = fork();
- ASSERT_NE(-1, child_pid);
- if (child_pid == 0) {
-
- char from_parent;
- EXPECT_EQ(1, read(pipe_to_child.getReadFD(), &from_parent,
- sizeof(from_parent)));
- EXPECT_EQ(0, from_parent);
- MemorySegmentMapped sgmt(mapped_file);
- void* ptr_child = sgmt.getNamedAddress("test address");
- EXPECT_TRUE(ptr_child);
- if (ptr_child) {
- const uint32_t val = *static_cast<const uint32_t*>(ptr_child);
- EXPECT_EQ(424242, val);
-
-
- const char ok = (val == 424242) ? 0 : 0xff;
- EXPECT_EQ(1, write(pipe_to_parent.getWriteFD(), &ok, sizeof(ok)));
- }
- exit(0);
- }
-
-
- segment_.reset(new MemorySegmentMapped(mapped_file));
- ptr = segment_->getNamedAddress("test address");
- ASSERT_TRUE(ptr);
- EXPECT_EQ(424242, *static_cast<const uint32_t*>(ptr));
- const char some_data = 0;
- EXPECT_EQ(1, write(pipe_to_child.getWriteFD(), &some_data,
- sizeof(some_data)));
-
- EXPECT_EQ(0, parentReadState(pipe_to_parent.getReadFD()));
- }
- TEST_F(MemorySegmentMappedTest, nullDeallocate) {
-
- EXPECT_NO_THROW(segment_->deallocate(0, 1024));
- EXPECT_TRUE(segment_->allMemoryDeallocated());
- }
- TEST_F(MemorySegmentMappedTest, shrink) {
- segment_->shrinkToFit();
-
-
-
-
- const size_t shrinked_size = segment_->getSize();
- EXPECT_GT(DEFAULT_INITIAL_SIZE, shrinked_size);
-
-
-
-
-
- segment_->shrinkToFit();
- EXPECT_EQ(shrinked_size, segment_->getSize());
-
- void* p = segment_->allocate(sizeof(uint32_t));
- segment_->deallocate(p, sizeof(uint32_t));
- }
- TEST_F(MemorySegmentMappedTest, violateReadOnly) {
-
-
-
- void* ptr = segment_->allocate(sizeof(uint32_t));
- segment_->setNamedAddress("test address", ptr);
- segment_.reset();
-
-
- if (!isc::util::unittests::runningOnValgrind()) {
- EXPECT_DEATH_IF_SUPPORTED({
- MemorySegmentMapped segment_ro(mapped_file);
- EXPECT_TRUE(segment_ro.getNamedAddress("test address"));
- *static_cast<uint32_t*>(
- segment_ro.getNamedAddress("test address")) = 0;
- }, "");
- }
-
-
-
- MemorySegmentMapped segment_ro(mapped_file);
- ptr = segment_ro.getNamedAddress("test address");
- EXPECT_NE(static_cast<void*>(NULL), ptr);
- EXPECT_THROW(segment_ro.deallocate(ptr, 4), MemorySegmentError);
- EXPECT_THROW(segment_ro.allocate(16), MemorySegmentError);
-
-
- EXPECT_THROW(segment_ro.allocate(DEFAULT_INITIAL_SIZE * 2),
- MemorySegmentError);
- EXPECT_THROW(segment_ro.setNamedAddress("test", NULL), MemorySegmentError);
- EXPECT_THROW(segment_ro.clearNamedAddress("test"), MemorySegmentError);
- EXPECT_THROW(segment_ro.shrinkToFit(), MemorySegmentError);
- }
- TEST_F(MemorySegmentMappedTest, getCheckSum) {
- const size_t old_cksum = segment_->getCheckSum();
-
-
-
-
-
- const size_t page_sz = boost::interprocess::mapped_region::get_page_size();
- uint8_t* cp0 = static_cast<uint8_t*>(segment_->allocate(page_sz));
- for (uint8_t* cp = cp0; cp < cp0 + page_sz; ++cp) {
- ++*cp;
- }
- EXPECT_EQ(old_cksum + 1, segment_->getCheckSum());
- }
- enum TestOpenMode {
- READER = 0,
- WRITER_FOR_WRITE,
- WRITER_OPEN_OR_CREATE,
- WRITER_CREATE_ONLY
- };
- void
- setSegment(TestOpenMode mode, scoped_ptr<MemorySegmentMapped>& sgmt_ptr) {
- switch (mode) {
- case READER:
- sgmt_ptr.reset(new MemorySegmentMapped(mapped_file));
- break;
- case WRITER_FOR_WRITE:
- sgmt_ptr.reset(new MemorySegmentMapped(mapped_file, OPEN_FOR_WRITE));
- break;
- case WRITER_OPEN_OR_CREATE:
- sgmt_ptr.reset(new MemorySegmentMapped(mapped_file, OPEN_OR_CREATE));
- break;
- case WRITER_CREATE_ONLY:
- sgmt_ptr.reset(new MemorySegmentMapped(mapped_file, CREATE_ONLY));
- break;
- }
- }
- void
- conflictCheck(TestOpenMode parent_mode, TestOpenMode child_mode) {
- PipeHolder pipe_to_child;
- PipeHolder pipe_to_parent;
- const pid_t child_pid = fork();
- ASSERT_NE(-1, child_pid);
- if (child_pid == 0) {
- char ch;
- EXPECT_EQ(1, read(pipe_to_child.getReadFD(), &ch, sizeof(ch)));
- ch = 0;
- try {
- scoped_ptr<MemorySegmentMapped> sgmt;
- setSegment(child_mode, sgmt);
- EXPECT_EQ(1, write(pipe_to_parent.getWriteFD(), &ch, sizeof(ch)));
- } catch (const MemorySegmentOpenError&) {
- ch = 1;
- EXPECT_EQ(1, write(pipe_to_parent.getWriteFD(), &ch, sizeof(ch)));
- }
- exit(0);
- }
-
-
- scoped_ptr<MemorySegmentMapped> sgmt;
- setSegment(parent_mode, sgmt);
- const char some_data = 0;
- EXPECT_EQ(1, write(pipe_to_child.getWriteFD(), &some_data,
- sizeof(some_data)));
-
-
- EXPECT_EQ(1, parentReadState(pipe_to_parent.getReadFD()));
- }
- TEST_F(MemorySegmentMappedTest, conflictReaderWriter) {
-
- if (isc::util::unittests::runningOnValgrind()) {
- return;
- }
-
-
- segment_.reset();
-
- conflictCheck(READER, WRITER_FOR_WRITE);
-
- conflictCheck(READER, WRITER_OPEN_OR_CREATE);
-
- conflictCheck(READER, WRITER_CREATE_ONLY);
-
- conflictCheck(WRITER_FOR_WRITE, READER);
-
- conflictCheck(WRITER_OPEN_OR_CREATE, READER);
-
- conflictCheck(WRITER_CREATE_ONLY, READER);
-
- conflictCheck(WRITER_FOR_WRITE, WRITER_FOR_WRITE);
-
- conflictCheck(WRITER_FOR_WRITE, WRITER_OPEN_OR_CREATE);
-
- conflictCheck(WRITER_FOR_WRITE, WRITER_CREATE_ONLY);
- }
- }
|