From: JINMEI Tatuya Date: Sat, 9 Mar 2013 19:58:17 +0000 (-0800) Subject: [2831] added get/set/clearNamedAddress interfaces X-Git-Tag: bind10-1.2.0beta1-release~457^2~119 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a3077227a49f8cd0ae4e7c1f20cc87c4844ef0fe;p=thirdparty%2Fkea.git [2831] added get/set/clearNamedAddress interfaces --- diff --git a/src/lib/util/memory_segment.h b/src/lib/util/memory_segment.h index 7d376a7f2a..b00c87f05c 100644 --- a/src/lib/util/memory_segment.h +++ b/src/lib/util/memory_segment.h @@ -34,6 +34,12 @@ public: isc::Exception(file, line, what) {} }; +class MemorySegmentError : public Exception { +public: + MemorySegmentError(const char* file, size_t line, const char* what) : + isc::Exception(file, line, what) {} +}; + /// \brief Memory Segment Class /// /// This class specifies an interface for allocating memory @@ -75,6 +81,19 @@ public: /// \return Returns true if all allocated memory was /// deallocated, false otherwise. virtual bool allMemoryDeallocated() const = 0; + + virtual void* getNamedAddress(const char* name) = 0; + + /// \brief TBD + /// + /// \c addr must be 0 (NULL) or an address that belongs to this segment. + /// The latter case means it must be the return value of a previous call + /// to \c allocate(). The actual implementation is encouraged to detect + /// violation of this restriction and signal it with an exception, but + /// it's not an API requirement. It's generally the caller's + /// responsibility to meet the restriction. + virtual void setNamedAddress(const char* name, void* addr) = 0; + virtual bool clearNamedAddress(const char* name) = 0; }; } // namespace util diff --git a/src/lib/util/memory_segment_local.cc b/src/lib/util/memory_segment_local.cc index 9c345c9040..024e0ce4a6 100644 --- a/src/lib/util/memory_segment_local.cc +++ b/src/lib/util/memory_segment_local.cc @@ -51,5 +51,19 @@ MemorySegmentLocal::allMemoryDeallocated() const { return (allocated_size_ == 0); } +void* +MemorySegmentLocal::getNamedAddress(const char* /*name*/) { + return (0); +} + +void +MemorySegmentLocal::setNamedAddress(const char* /*name*/, void* /*addr*/) { +} + +bool +MemorySegmentLocal::clearNamedAddress(const char* /*name*/) { + return (false); +} + } // namespace util } // namespace isc diff --git a/src/lib/util/memory_segment_local.h b/src/lib/util/memory_segment_local.h index de35b87db1..c6917e031a 100644 --- a/src/lib/util/memory_segment_local.h +++ b/src/lib/util/memory_segment_local.h @@ -63,6 +63,10 @@ public: /// deallocated, false otherwise. virtual bool allMemoryDeallocated() const; + virtual void* getNamedAddress(const char* name); + virtual void setNamedAddress(const char* name, void* addr); + virtual bool clearNamedAddress(const char* name); + private: // allocated_size_ can underflow, wrap around to max size_t (which // is unsigned). But because we only do a check against 0 and not a diff --git a/src/lib/util/memory_segment_mapped.cc b/src/lib/util/memory_segment_mapped.cc index d5e1adc528..bf99c668f7 100644 --- a/src/lib/util/memory_segment_mapped.cc +++ b/src/lib/util/memory_segment_mapped.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -25,6 +26,8 @@ using boost::interprocess::managed_mapped_file; using boost::interprocess::open_or_create; using boost::interprocess::open_only; +using boost::interprocess::open_read_only; +using boost::interprocess::offset_ptr; namespace isc { namespace util { @@ -36,9 +39,11 @@ struct MemorySegmentMapped::Impl { initial_size)) {} - Impl(const std::string& filename) : + Impl(const std::string& filename, bool read_only) : filename_(filename), - base_sgmt_(new managed_mapped_file(open_only, filename.c_str())) + base_sgmt_(read_only ? + new managed_mapped_file(open_read_only, filename.c_str()) : + new managed_mapped_file(open_only, filename.c_str())) {} // mapped file; remember it in case we need to grow it. @@ -52,7 +57,7 @@ MemorySegmentMapped::MemorySegmentMapped(const std::string& filename) : impl_(0) { try { - impl_ = new Impl(filename); + impl_ = new Impl(filename, true); } catch (const boost::interprocess::interprocess_exception& ex) { isc_throw(MemorySegmentOpenError, "failed to open mapped memory segment for " << filename @@ -68,7 +73,7 @@ MemorySegmentMapped::MemorySegmentMapped(const std::string& filename, if (create) { impl_ = new Impl(filename, initial_size); } else { - impl_ = new Impl(filename); + impl_ = new Impl(filename, false); } } catch (const boost::interprocess::interprocess_exception& ex) { isc_throw(MemorySegmentOpenError, @@ -134,6 +139,31 @@ MemorySegmentMapped::allMemoryDeallocated() const { return (impl_->base_sgmt_->all_memory_deallocated()); } +void* +MemorySegmentMapped::getNamedAddress(const char* name) { + offset_ptr* storage = + impl_->base_sgmt_->find >(name).first; + if (storage) { + return (storage->get()); + } + return (0); +} + +void +MemorySegmentMapped::setNamedAddress(const char* name, void* addr) { + if (addr && !impl_->base_sgmt_->belongs_to_segment(addr)) { + isc_throw(MemorySegmentError, "out of segment address: " << addr); + } + offset_ptr* storage = + impl_->base_sgmt_->find_or_construct >(name)(); + *storage = addr; +} + +bool +MemorySegmentMapped::clearNamedAddress(const char* name) { + return (impl_->base_sgmt_->destroy >(name)); +} + size_t MemorySegmentMapped::getSize() const { return (impl_->base_sgmt_->get_size()); diff --git a/src/lib/util/memory_segment_mapped.h b/src/lib/util/memory_segment_mapped.h index 2937e53797..46242a2c1c 100644 --- a/src/lib/util/memory_segment_mapped.h +++ b/src/lib/util/memory_segment_mapped.h @@ -62,6 +62,16 @@ public: virtual bool allMemoryDeallocated() const; + virtual void* getNamedAddress(const char* name); + + /// \brief TBD + /// + /// This implementation detects if \c addr is invalid (see the base class + /// description) and throws \c MemorySegmentError in that case. + virtual void setNamedAddress(const char* name, void* addr); + + virtual bool clearNamedAddress(const char* name); + size_t getSize() const; private: diff --git a/src/lib/util/tests/memory_segment_mapped_unittest.cc b/src/lib/util/tests/memory_segment_mapped_unittest.cc index 2994f9d4df..4f24100384 100644 --- a/src/lib/util/tests/memory_segment_mapped_unittest.cc +++ b/src/lib/util/tests/memory_segment_mapped_unittest.cc @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -178,6 +179,83 @@ TEST_F(MemorySegmentMappedTest, badDeallocate) { EXPECT_TRUE(segment_->allMemoryDeallocated()); } +TEST_F(MemorySegmentMappedTest, namedAddress) { + // If not exist, null pointer will be returned. + EXPECT_EQ(static_cast(0), segment_->getNamedAddress("test address")); + + // Now set it + void* ptr32 = segment_->allocate(sizeof(uint32_t)); + const uint32_t test_val = 42; + std::memcpy(ptr32, &test_val, sizeof(test_val)); + segment_->setNamedAddress("test address", ptr32); + + // we can now get it; the stored value should be intact. + EXPECT_EQ(ptr32, segment_->getNamedAddress("test address")); + EXPECT_EQ(test_val, *static_cast(ptr32)); + + // Override it. + void* ptr16 = segment_->allocate(sizeof(uint16_t)); + const uint16_t test_val16 = 4200; + std::memcpy(ptr16, &test_val16, sizeof(test_val16)); + segment_->setNamedAddress("test address", ptr16); + EXPECT_EQ(ptr16, segment_->getNamedAddress("test address")); + EXPECT_EQ(test_val16, *static_cast(ptr16)); + + // Clear it. Then we won't be able to find it any more. + EXPECT_TRUE(segment_->clearNamedAddress("test address")); + EXPECT_EQ(static_cast(0), segment_->getNamedAddress("test address")); + + // duplicate attempt of clear will result in false as it doesn't exist. + EXPECT_FALSE(segment_->clearNamedAddress("test address")); + + // Setting NULL is okay. + segment_->setNamedAddress("null address", 0); + EXPECT_EQ(static_cast(0), segment_->getNamedAddress("null address")); + + // Setting or out-of-segment address is prohibited, and this implementation + // detects and rejects it. + uint8_t ch = 'A'; + EXPECT_THROW(segment_->setNamedAddress("local address", &ch), + MemorySegmentError); + + // Set it again and read it in the read-only mode. + segment_->setNamedAddress("test address", ptr16); + MemorySegmentMapped segment_ro(mapped_file); + EXPECT_TRUE(segment_ro.getNamedAddress("test address")); + EXPECT_EQ(test_val16, *static_cast( + segment_ro.getNamedAddress("test address"))); + EXPECT_EQ(static_cast(0), + segment_ro.getNamedAddress("null address")); + + // clean them up all + segment_->deallocate(ptr32, sizeof(uint32_t)); + segment_->deallocate(ptr16, sizeof(uint32_t)); + EXPECT_TRUE(segment_->clearNamedAddress("test address")); + EXPECT_TRUE(segment_->clearNamedAddress("null address")); + EXPECT_TRUE(segment_->allMemoryDeallocated()); +} + +TEST_F(MemorySegmentMappedTest, violateReadOnly) { + // If the segment is opened in the read only mode, modification attempt + // will result in crash. + EXPECT_DEATH_IF_SUPPORTED({ + MemorySegmentMapped segment_ro(mapped_file); + segment_ro.allocate(16); + }, ""); + EXPECT_DEATH_IF_SUPPORTED({ + MemorySegmentMapped segment_ro(mapped_file); + segment_ro.setNamedAddress("test", 0); + }, ""); + EXPECT_DEATH_IF_SUPPORTED({ + void* ptr = segment_->allocate(sizeof(uint32_t)); + segment_->setNamedAddress("test address", ptr); + MemorySegmentMapped segment_ro(mapped_file); + EXPECT_TRUE(segment_ro.getNamedAddress("test address")); + *static_cast( + segment_ro.getNamedAddress("test address")) = 0; + }, ""); +} + /* TEST(MemorySegmentLocal, TestNullDeallocate) { auto_ptr segment(new MemorySegmentLocal());