]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[2831] added get/set/clearNamedAddress interfaces
authorJINMEI Tatuya <jinmei@isc.org>
Sat, 9 Mar 2013 19:58:17 +0000 (11:58 -0800)
committerJINMEI Tatuya <jinmei@isc.org>
Sat, 9 Mar 2013 19:58:17 +0000 (11:58 -0800)
src/lib/util/memory_segment.h
src/lib/util/memory_segment_local.cc
src/lib/util/memory_segment_local.h
src/lib/util/memory_segment_mapped.cc
src/lib/util/memory_segment_mapped.h
src/lib/util/tests/memory_segment_mapped_unittest.cc

index 7d376a7f2a7318552f30a892fe82a93ae6b4ceb0..b00c87f05cfa39e22596d82e8e1fedae3e1a4c58 100644 (file)
@@ -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 <code>true</code> if all allocated memory was
     /// deallocated, <code>false</code> 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
index 9c345c9040dfd66a038ecb52c7ca8af3ea2b0553..024e0ce4a6f1396d022fd8114f7d205a7ece26d3 100644 (file)
@@ -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
index de35b87db1f41b18093b516e75432cdf775d1e22..c6917e031a05fb1c0665ff9dfd4c600b25f6903e 100644 (file)
@@ -63,6 +63,10 @@ public:
     /// deallocated, <code>false</code> 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
index d5e1adc52894ef2112e7c904981800cf56cc9a57..bf99c668f7c59d10b26108671dbf041cef1d14ca 100644 (file)
@@ -17,6 +17,7 @@
 #include <boost/scoped_ptr.hpp>
 #include <boost/interprocess/exceptions.hpp>
 #include <boost/interprocess/managed_mapped_file.hpp>
+#include <boost/interprocess/offset_ptr.hpp>
 
 #include <cassert>
 #include <string>
@@ -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<void>* storage =
+        impl_->base_sgmt_->find<offset_ptr<void> >(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<void>* storage =
+        impl_->base_sgmt_->find_or_construct<offset_ptr<void> >(name)();
+    *storage = addr;
+}
+
+bool
+MemorySegmentMapped::clearNamedAddress(const char* name) {
+    return (impl_->base_sgmt_->destroy<offset_ptr<void> >(name));
+}
+
 size_t
 MemorySegmentMapped::getSize() const {
     return (impl_->base_sgmt_->get_size());
index 2937e537973ccfe273a90bb2b83ade53af35e9c7..46242a2c1ccf02de7bdf2cae37d5352bebe1474a 100644 (file)
@@ -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:
index 2994f9d4df64648f606f8979678147d45024b646..4f24100384fbae051a8dbc3db2dd27877756da0d 100644 (file)
@@ -20,6 +20,7 @@
 #include <boost/scoped_ptr.hpp>
 
 #include <cstdlib>
+#include <cstring>
 #include <limits>
 #include <stdexcept>
 
@@ -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<void*>(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<const uint32_t*>(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<const uint16_t*>(ptr16));
+
+    // Clear it.  Then we won't be able to find it any more.
+    EXPECT_TRUE(segment_->clearNamedAddress("test address"));
+    EXPECT_EQ(static_cast<void*>(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<void*>(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<const uint16_t*>(
+                  segment_ro.getNamedAddress("test address")));
+    EXPECT_EQ(static_cast<void*>(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<uint32_t*>(
+                segment_ro.getNamedAddress("test address")) = 0;
+        }, "");
+}
+
 /*
 TEST(MemorySegmentLocal, TestNullDeallocate) {
     auto_ptr<MemorySegment> segment(new MemorySegmentLocal());