BIND 10 master, updated. e9fa118cd1b9d4d1c47ddb94244ddf78266c9dbd [master] Merge branch 'trac2831'

BIND 10 source code commits bind10-changes at lists.isc.org
Tue Apr 30 05:54:16 UTC 2013


The branch, master has been updated
       via  e9fa118cd1b9d4d1c47ddb94244ddf78266c9dbd (commit)
       via  e825b22e4ea06a8f0ecc8645fbd42af230d05151 (commit)
       via  a2fcb467b96cb4229e35330a9ca72db8065953bb (commit)
       via  d70fad8d81f6fb7a4dcadcad45043c76e85f58af (commit)
       via  329d5b2238df1813bde496a44a31c0e57dbbac00 (commit)
       via  0f6cfdfd2a611d2a440fcb01596c4f6173e9ee04 (commit)
       via  3877992c69722447eeb9e4819bdadc64fb44754c (commit)
       via  059b6a3e1f0c3c9a5d4526664d272f16bb664903 (commit)
       via  510d6d2e9f16f9bf1dfff251d84e311b685fd454 (commit)
       via  e41c43c1cc533686b04734fa35377bbaebf356ea (commit)
       via  e3b63fb33c64d7cafbc59895c803b5ed7ddeb82a (commit)
       via  8297b3a7425d2a0de1f1f0f5cb1a4572a1780820 (commit)
       via  6eae3579a0dc0ed27f33c3e36cec2ad64be7329d (commit)
       via  d43543b1fea006c3ac4bca51749e7cffbcc84085 (commit)
       via  2a70916c9d0949f710a3f289ef13925bdf12dd5d (commit)
       via  3469f1a8757e2b49c29aa93513c64a5167dff400 (commit)
       via  408b43df795d7dbb4ee9d4a47cb3e4ae9ae1bba6 (commit)
       via  52c3dae27c25e3aa3e32ae300013ddecec5ff190 (commit)
       via  c936d8ec97816a35aafd54aa4c06fb8e5b5689eb (commit)
       via  c1465e69b3d272bf4867d99e47c63659f41c4db3 (commit)
       via  36389eed513783f9ccb0b7248fe0c5909ef2a36d (commit)
       via  5728c385420fdb47dd463c7737ee0cf447609c81 (commit)
       via  caa37a99fc07eec6e88c6a829d000b2cb1baf4d6 (commit)
       via  ba0d6139cadca933ebbaaa7f5016480154331ae6 (commit)
       via  9c36d2e22389ed7c9ae61fc91eb3f2946b10c169 (commit)
       via  00b7af245214cfdc54f522d719f23406d80d68ad (commit)
       via  d17b3c006757eecc1fab20cec90ead3e23b5962b (commit)
       via  08a77e0ef2096158eff12b5d20e9af9e46c93c45 (commit)
       via  e01ee176ce2071c076833c842a9cd946a5008130 (commit)
       via  be5ebe7673a8335d929803553bf3fce041a76bce (commit)
       via  bafbce54b6b042ff5fcf7bafc18b316c030f08c0 (commit)
       via  da33bc422e11f1cbf33427659a14291a32256833 (commit)
       via  2772477dcf13e7c524cfdaf4e39323f0716404dc (commit)
       via  faca56aea56b9eafd1093d06234650ea311a667d (commit)
       via  54fdd6d60c068faaac34d573acb095378672f47e (commit)
       via  0b18c4d0297e5e37ef0584b5e56912cc02715021 (commit)
       via  c52e7d7d0cfbdfbf4d7342f32024fdf4cae567c3 (commit)
       via  8599372b7fcf5a21c873d43189684b681b63307d (commit)
       via  ecc1ba7e65eaa8371cfdd8b83946c6a3bc2e5ee8 (commit)
       via  b38ed8f456895a7cb262b1b8cadadddc68964e6c (commit)
       via  5ab82e00091c504afeb54037a60671d344233512 (commit)
       via  3c93e56397f0af33064d449da82ca69d535a251a (commit)
       via  81e57da07f3b1a718fdd81991692e703f083219d (commit)
       via  b8d905c9dffd7f3973854d9f1bc7eac7086f4aa2 (commit)
       via  693068bdb12a36936d221f432e447afae6b05dc1 (commit)
       via  f6dae94a7b648f7fc766109c4f4c13152d45aa9b (commit)
       via  0f5e915ace1384308c9976c5f20dd49d5b2d05ab (commit)
       via  10d88f05a9705a4fb14afd6ceb89e976e3c195d0 (commit)
       via  617f1e6fc0da5415c244c45c211cae4f01b68585 (commit)
       via  8ddec7d1255e11ffaf69c7c827b42aeb69f95872 (commit)
       via  b215e58d58791c27f6116f65b66243b7a54ec14b (commit)
       via  58825bde4cbb00eb52ff5bc31a1d170594a26d87 (commit)
       via  5d1b066a7702c075d7934a3ce88181b1c02da878 (commit)
       via  b610eee2708d9c1783384c850896c6203ccc3dd2 (commit)
       via  58f99ec6977a07a6df8f7053d2e03201245491fd (commit)
       via  e9e336900ee014c251ad4b25a8e19d36da3a9a2e (commit)
       via  7ed3411dd5f0045b2eb877579a715de9892fc501 (commit)
       via  86c303a0291366a0f3dc7918255f2708ff1409e9 (commit)
       via  29b1d8dc4aafc4f644b3acd36dd6ca1704c07543 (commit)
       via  639532ca50d317fdee78374be0e05c0c43ee2a0d (commit)
       via  e1126a32146e14b8816b7a3fb733f3836ca61379 (commit)
       via  252e7844e40e29ba6a7a30498bf525b75deb8219 (commit)
       via  67d05b954c47821d6a29ba093632604c49fb794c (commit)
       via  2f6c7ab36c4c2c88bc19503a2bf5577d148cb71b (commit)
       via  8a09c89d47dd66c641809fadca16d29eb79c25f4 (commit)
       via  229916f0c84ee62b3c0f3c204d6b20dd3e8d3062 (commit)
       via  4a6f54f71484ebc8531371da819d4f98f59418e9 (commit)
       via  14023798bdf7385a96500cf8bb7d93d485def18a (commit)
       via  8e75dec19bbdb3ae1e01558ed5bb8cd89ad45582 (commit)
       via  bb5479f56b9bdab1eff81e8ecca1d8e703a9ef50 (commit)
       via  2fb93c012e0c3f8a5e8e0fff208abe5685b7d4ce (commit)
       via  27ae48b404de59c031c7f97f64edd4056c5e62dc (commit)
       via  643e32a402aa9dcfbf9d7df47495c77474eeffe8 (commit)
       via  a2ea0fb9c996d174936122809275cc464cd2e17c (commit)
       via  2bc9bc74ea4450a1581ffcaf5f1598a4c03d3721 (commit)
       via  0fccc0c84fb7706ff71039896564c5496f0cb7ed (commit)
       via  d7647f9c62f62e2115947ec0f1aaea57cc266b0b (commit)
       via  111e2c83f6584bc452e5658f17779b30d2959c99 (commit)
       via  c2d22d81551f2309538404b52615d04394a3b9c3 (commit)
       via  a3077227a49f8cd0ae4e7c1f20cc87c4844ef0fe (commit)
       via  685c9b375d73134e0c59ba8c7623f74487f69348 (commit)
       via  4cfe351f170077546b2187f9d33d41b4148aa6a0 (commit)
       via  042bfd80328dd3c5888ac70630f1545aba82f125 (commit)
       via  d46357aadcf46d1be0be68fd510d9065ecba2a57 (commit)
      from  bf06401cd681a172444c7a07b8f99083be86a508 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit e9fa118cd1b9d4d1c47ddb94244ddf78266c9dbd
Merge: bf06401 e825b22
Author: JINMEI Tatuya <jinmei at isc.org>
Date:   Mon Apr 29 22:02:08 2013 -0700

    [master] Merge branch 'trac2831'

-----------------------------------------------------------------------

Summary of changes:
 configure.ac                                       |   11 +
 m4macros/ax_boost_for_bind10.m4                    |   49 +-
 src/lib/util/Makefile.am                           |   15 +
 src/lib/util/memory_segment.h                      |  253 +++++++-
 src/lib/util/memory_segment_local.cc               |   23 +-
 src/lib/util/memory_segment_local.h                |   32 +
 src/lib/util/memory_segment_mapped.cc              |  382 ++++++++++++
 src/lib/util/memory_segment_mapped.h               |  261 ++++++++
 src/lib/util/tests/Makefile.am                     |    6 +
 .../util/tests/interprocess_sync_file_unittest.cc  |   38 +-
 .../tests/interprocess_util.cc}                    |   43 +-
 .../tests/interprocess_util.h}                     |   28 +-
 .../util/tests/memory_segment_common_unittest.cc   |   92 +++
 .../tests/memory_segment_common_unittest.h}        |   27 +-
 .../util/tests/memory_segment_local_unittest.cc    |    9 +-
 .../util/tests/memory_segment_mapped_unittest.cc   |  620 ++++++++++++++++++++
 16 files changed, 1798 insertions(+), 91 deletions(-)
 create mode 100644 src/lib/util/memory_segment_mapped.cc
 create mode 100644 src/lib/util/memory_segment_mapped.h
 copy src/lib/{dns/python/zone_checker_python.h => util/tests/interprocess_util.cc} (60%)
 copy src/lib/{dns/python/zone_checker_python.h => util/tests/interprocess_util.h} (67%)
 create mode 100644 src/lib/util/tests/memory_segment_common_unittest.cc
 copy src/lib/{dns/python/zone_checker_python.h => util/tests/memory_segment_common_unittest.h} (59%)
 create mode 100644 src/lib/util/tests/memory_segment_mapped_unittest.cc

-----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index eff05ec..3f74c52 100644
--- a/configure.ac
+++ b/configure.ac
@@ -884,6 +884,17 @@ if test "$BOOST_NUMERIC_CAST_WOULDFAIL" = "yes" -a X"$werror_ok" = X1 -a $CLANGP
     AC_MSG_ERROR([Failed to compile a required header file.  If you are using FreeBSD and Boost installed via ports, retry with specifying --without-werror.  See the ChangeLog entry for Trac no. 1991 for more details.])
 fi
 
+use_shared_memory=yes
+AC_ARG_WITH(shared-memory,
+    AC_HELP_STRING([--with-shared-memory],
+    [Build with Boost shared memory support; for large scale authoritative DNS servers]),
+    [use_shared_memory=$withval])
+if test X$use_shared_memory = Xyes -a "$BOOST_MAPPED_FILE_WOULDFAIL" = "yes"; then
+    AC_MSG_ERROR([Boost shared memory does not compile on this system.  If you don't need it (most normal users won't) build without it; using a different compiler or a different version of Boost may also help.])
+fi
+AM_CONDITIONAL([USE_SHARED_MEMORY], [test x$use_shared_memory = xyes])
+AC_SUBST(BOOST_MAPPED_FILE_CXXFLAG)
+
 # Add some default CPP flags needed for Boost, identified by the AX macro.
 CPPFLAGS="$CPPFLAGS $CPPFLAGS_BOOST_THREADCONF"
 
diff --git a/m4macros/ax_boost_for_bind10.m4 b/m4macros/ax_boost_for_bind10.m4
index 1ce367e..577af6b 100644
--- a/m4macros/ax_boost_for_bind10.m4
+++ b/m4macros/ax_boost_for_bind10.m4
@@ -23,7 +23,11 @@ dnl   BOOST_OFFSET_PTR_WOULDFAIL set to "yes" if offset_ptr would cause build
 dnl                              error; otherwise set to "no"
 dnl   BOOST_NUMERIC_CAST_WOULDFAIL set to "yes" if numeric_cast would cause
 dnl                                build error; otherwise set to "no"
-dnl
+dnl   BOOST_MAPPED_FILE_WOULDFAIL set to "yes" if managed_mapped_file would
+dnl                               cause build failure; otherwise set to "no"
+dnl   BOOST_MAPPED_FILE_CXXFLAG set to the compiler flag that would need to
+dnl                             compile managed_mapped_file (can be empty).
+dnl                             It is of no use if "WOULDFAIL" is yes.
 
 AC_DEFUN([AX_BOOST_FOR_BIND10], [
 AC_LANG_SAVE
@@ -101,10 +105,49 @@ if test "X$GXX" = "Xyes"; then
 
    CXXFLAGS="$CXXFLAGS_SAVED"
 else
-  # This doesn't matter for non-g++
-  BOOST_NUMERIC_CAST_WOULDFAIL=no
+   # This doesn't matter for non-g++
+   BOOST_NUMERIC_CAST_WOULDFAIL=no
 fi
 
+# Boost interprocess::managed_mapped_file is highly system dependent and
+# can cause many portability issues.  We are going to check if it could
+# compile at all, possibly with being lenient about compiler warnings.
+BOOST_MAPPED_FILE_WOULDFAIL=yes
+BOOST_MAPPED_FILE_CXXFLAG=
+CXXFLAGS_SAVED="$CXXFLAGS"
+try_flags="no"
+if test "X$GXX" = "Xyes"; then
+  CXXFLAGS="$CXXFLAGS -Wall -Wextra -Werror"
+  try_flags="$try_flags -Wno-error"
+fi
+# clang can cause false positives with -Werror without -Qunused-arguments
+AC_CHECK_DECL([__clang__], [CXXFLAGS="$CXXFLAGS -Qunused-arguments"], [])
+
+AC_MSG_CHECKING([Boost managed_mapped_file compiles])
+CXXFLAGS_SAVED2="$CXXFLAGS"
+for flag in $try_flags; do
+  if test "$flag" != no; then
+    BOOST_MAPPED_FILE_CXXFLAG="$flag"
+  fi
+  CXXFLAGS="$CXXFLAGS $BOOST_MAPPED_FILE_CXXFLAG"
+  AC_TRY_COMPILE([
+  #include <boost/interprocess/managed_mapped_file.hpp>
+  ],[
+  return (boost::interprocess::managed_mapped_file().all_memory_deallocated());
+  ],[AC_MSG_RESULT([yes, with $flag flag])
+     BOOST_MAPPED_FILE_WOULDFAIL=no
+     break
+  ],[])
+
+  CXXFLAGS="$CXXFLAGS_SAVED2"
+done
+
+if test $BOOST_MAPPED_FILE_WOULDFAIL = yes; then
+  AC_MSG_RESULT(no)
+fi
+
+CXXFLAGS="$CXXFLAGS_SAVED"
+
 AC_SUBST(BOOST_INCLUDES)
 
 CPPFLAGS="$CPPFLAGS_SAVED"
diff --git a/src/lib/util/Makefile.am b/src/lib/util/Makefile.am
index 3960a8b..32a9341 100644
--- a/src/lib/util/Makefile.am
+++ b/src/lib/util/Makefile.am
@@ -6,6 +6,18 @@ AM_CPPFLAGS += -I$(top_srcdir)/src/lib/exceptions -I$(top_builddir)/src/lib/exce
 AM_CPPFLAGS += $(BOOST_INCLUDES)
 AM_CPPFLAGS += -DLOCKFILE_DIR=\"${localstatedir}/${PACKAGE_NAME}\"
 AM_CXXFLAGS = $(B10_CXXFLAGS)
+# If we use the shared-memory support, corresponding Boost library may
+# cause build failures especially if it's strict about warnings.  We've
+# detected it in ./configure and set BOOST_MAPPED_FILE_CXXFLAG to be more
+# lenient as necessary (specifically, when set it'd usually suppress -Werror).
+# This is a module wide setting, and has a possible bad side effect of hiding
+# issues in other files, but making it per-file seems to be too costly.
+# So we begin with the wider setting. If the side effect turns out to be too
+# harmful, we'll consider other measure, e.g, moving the related files into
+# a subdirectory.
+if USE_SHARED_MEMORY
+AM_CXXFLAGS += $(BOOST_MAPPED_FILE_CXXFLAG)
+endif
 
 lib_LTLIBRARIES = libb10-util.la
 libb10_util_la_SOURCES  = filename.h filename.cc
@@ -18,6 +30,9 @@ libb10_util_la_SOURCES += interprocess_sync_file.h interprocess_sync_file.cc
 libb10_util_la_SOURCES += interprocess_sync_null.h interprocess_sync_null.cc
 libb10_util_la_SOURCES += memory_segment.h
 libb10_util_la_SOURCES += memory_segment_local.h memory_segment_local.cc
+if USE_SHARED_MEMORY
+libb10_util_la_SOURCES += memory_segment_mapped.h memory_segment_mapped.cc
+endif
 libb10_util_la_SOURCES += range_utilities.h
 libb10_util_la_SOURCES += hash/sha1.h hash/sha1.cc
 libb10_util_la_SOURCES += encode/base16_from_binary.h
diff --git a/src/lib/util/memory_segment.h b/src/lib/util/memory_segment.h
index 664bd3c..e62c9df 100644
--- a/src/lib/util/memory_segment.h
+++ b/src/lib/util/memory_segment.h
@@ -15,27 +15,107 @@
 #ifndef MEMORY_SEGMENT_H
 #define MEMORY_SEGMENT_H
 
+#include <exceptions/exceptions.h>
+
 #include <stdlib.h>
 
 namespace isc {
 namespace util {
 
+/// \brief Exception that can be thrown when constructing a MemorySegment
+/// object.
+class MemorySegmentOpenError : public Exception {
+public:
+    MemorySegmentOpenError(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) {}
+};
+
+/// \brief Exception that is thrown, when allocating space in a MemorySegment
+/// results in growing the underlying segment.
+///
+/// See MemorySegment::allocate() for details.
+class MemorySegmentGrown : public Exception {
+public:
+    MemorySegmentGrown(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) {}
+};
+
+/// \brief General error that can be thrown by a MemorySegment
+/// implementation.
+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
-/// segments. This is an abstract class and a real
-/// implementation such as MemorySegmentLocal should be used
-/// in code.
+/// This class specifies an interface for allocating memory segments.
+/// It's intended to provide a unified interface, whether the underlying
+/// memory is local to a specific process or is sharable by multiple
+/// processes.
+///
+/// This is an abstract class and a real implementation such as
+/// MemorySegmentLocal should be used in code.
 class MemorySegment {
 public:
     /// \brief Destructor
     virtual ~MemorySegment() {}
 
-    /// \brief Allocate/acquire a segment of memory. The source of the
-    /// memory is dependent on the implementation used.
+    /// \brief Allocate/acquire a fragment of memory.
     ///
-    /// Throws <code>std::bad_alloc</code> if the implementation cannot
-    /// allocate the requested storage.
+    /// The source of the memory is dependent on the implementation used.
+    ///
+    /// Depending on the implementation details, it may have to grow the
+    /// internal memory segment (again, in an implementation dependent way)
+    /// to allocate the required size of memory.  In that case the
+    /// implementation must grow the internal segment sufficiently so the
+    /// next call to allocate() for the same size will succeed, and throw
+    /// a \c MemorySegmentGrown exception (not really allocating the memory
+    /// yet).
+    ///
+    /// An application that uses this memory segment abstraction to allocate
+    /// memory should expect this exception, and should normally catch it
+    /// at an appropriate layer (which may be immediately after a call to
+    /// \c allocate() or a bit higher layer).  It should interpret the
+    /// exception as any raw address that belongs to the segment may have
+    /// been remapped and must be re-fetched via an already established
+    /// named address using the \c getNamedAddress() method.
+    ///
+    /// The intended use case of \c allocate() with the \c MemorySegmentGrown
+    /// exception is to build a complex object that would internally require
+    /// multiple calls to \c allocate():
+    ///
+    /// \code
+    /// ComplicatedStuff* stuff = NULL;
+    /// while (!stuff) { // this must eventually succeed or result in bad_alloc
+    ///     try {
+    ///         // create() is a factory method that takes a memory segment
+    ///         // and calls allocate() on it multiple times.  create()
+    ///         // provides an exception guarantee that any intermediately
+    ///         // allocated memory will be properly deallocate()-ed on
+    ///         // exception.
+    ///         stuff = ComplicatedStuff::create(mem_segment);
+    ///     } catch (const MemorySegmentGrown&) { /* just try again */ }
+    /// }
+    /// \endcode
+    ///
+    /// This way, \c create() can be written as if each call to \c allocate()
+    /// always succeeds.
+    ///
+    /// Alternatively, or in addition to this, we could introduce a "no throw"
+    /// version of this method with a way to tell the caller the reason of
+    /// any failure (whether it's really out of memory or just due to growing
+    /// the segment).  That would be more convenient if the caller wants to
+    /// deal with the failures on a per-call basis rather than as a set
+    /// of calls like in the above example.  At the moment, we don't expect
+    /// to have such use-cases, so we only provide the exception
+    /// version.
+    ///
+    /// \throw std::bad_alloc The implementation cannot allocate the
+    /// requested storage.
+    /// \throw MemorySegmentGrown The memory segment doesn't have sufficient
+    /// space for the requested size and has grown internally.
     ///
     /// \param size The size of the memory requested in bytes.
     /// \return Returns pointer to the memory allocated.
@@ -50,6 +130,18 @@ public:
     /// use this argument in some implementations to test if all allocated
     /// memory was deallocated properly.
     ///
+    /// Specific implementation may also throw \c MemorySegmentError if it
+    /// encounters violation of implementation specific restrictions.
+    ///
+    /// In general, however, this method must succeed and exception free
+    /// as long as the caller passes valid parameters (\c ptr specifies
+    /// memory previously allocated and \c size is correct).
+    ///
+    /// \throw OutOfRange The passed size doesn't match the allocated memory
+    /// size (when identifiable for the implementation).
+    /// \throw MemorySegmentError Failure of implementation specific
+    /// validation.
+    ///
     /// \param ptr Pointer to the block of memory to free/release. This
     /// should be equal to a value returned by <code>allocate()</code>.
     /// \param size The size of the memory to be freed in bytes. This
@@ -58,12 +150,155 @@ public:
 
     /// \brief Check if all allocated memory was deallocated.
     ///
-    /// \return Returns <code>true</code> if all allocated memory was
+    /// \return Returns <code>true</code> if all allocated memory (including
+    /// names associated by memory addresses by \c setNamedAddress()) was
     /// deallocated, <code>false</code> otherwise.
     virtual bool allMemoryDeallocated() const = 0;
+
+    /// \brief Associate specified address in the segment with a given name.
+    ///
+    /// This method establishes an association between the given name and
+    /// the address in an implementation specific way.  The stored address
+    /// is retrieved by the name later by calling \c getNamedAddress().
+    /// If the underlying memory segment is sharable by multiple processes,
+    /// the implementation must ensure the portability of the association;
+    /// if a process gives an address in the shared segment a name, another
+    /// process that shares the same segment should be able to retrieve the
+    /// corresponding address by that name (in such cases the real address
+    /// may be different between these two processes).
+    ///
+    /// \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.  Note that NULL is allowed
+    /// as \c addr even if it wouldn't be considered to "belong to" the
+    /// segment in its normal sense; it can be used to indicate that memory
+    /// has not been allocated for the specified name.  A subsequent call
+    /// to \c getNamedAddress() will return NULL for that name.
+    ///
+    /// \note Naming an address is intentionally separated from allocation
+    /// so that, for example, one module of a program can name a memory
+    /// region allocated by another module of the program.
+    ///
+    /// There can be an existing association for the name; in that case the
+    /// association will be overridden with the newly given address.
+    ///
+    /// While normally unexpected, it's possible that available space in the
+    /// segment is not sufficient to allocate a space (if not already exist)
+    /// for the specified name in the segment.  In that case, if possible, the
+    /// implementation should try to grow the internal segment and retry
+    /// establishing the association.  The implementation should throw
+    /// std::bad_alloc if even reasonable attempts of retry still fail.
+    ///
+    /// This method should normally return false, but if the internal segment
+    /// had to grow to store the given name, it must return true.  The
+    /// application should interpret it just like the case of
+    /// \c MemorySegmentGrown exception thrown from the \c allocate() method.
+    ///
+    /// \note The behavior in case the internal segment grows is different
+    /// from that of \c allocate().  This is intentional.  In intended use
+    /// cases (for the moment) this method will be called independently,
+    /// rather than as part of a set of allocations.  It's also expected
+    /// that other raw memory addresses (which would have been invalidated
+    /// due to the change to the segment) won't be referenced directly
+    /// immediately after this call.  So, the caller should normally be able
+    /// to call this method as mostly never-fail one (except in case of real
+    /// memory exhaustion) and ignore the return value.
+    ///
+    /// \throw std::bad_alloc Allocation of a segment space for the given name
+    /// failed.
+    /// \throw InvalidParameter name is NULL.
+    /// \throw MemorySegmentError Failure of implementation specific
+    /// validation.
+    ///
+    /// \param name A C string to be associated with \c addr. Must not be NULL.
+    /// \param addr A memory address returned by a prior call to \c allocate.
+    /// \return true if the internal segment has grown to allocate space for
+    /// the name; false otherwise (see above).
+    bool setNamedAddress(const char* name, void* addr) {
+        // This public method implements common validation.  The actual
+        // work specific to the derived segment is delegated to the
+        // corresponding protected method.
+        if (!name) {
+            isc_throw(InvalidParameter,
+                      "NULL name is given to setNamedAddress");
+        }
+        return (setNamedAddressImpl(name, addr));
+    }
+
+    /// \brief Return the address in the segment that has the given name.
+    ///
+    /// This method returns the memory address in the segment corresponding
+    /// to the specified \c name.  The name and address must have been
+    /// associated by a prior call to \c setNameAddress().  If no address
+    /// associated with the given name is found, it returns NULL.
+    ///
+    /// This method should generally be considered exception free, but there
+    /// can be a small chance it throws, depending on the internal
+    /// implementation (e.g., if it converts the name to std::string), so the
+    /// API doesn't guarantee that property.  In general, if this method
+    /// throws it should be considered a fatal condition.
+    ///
+    /// \throw InvalidParameter name is NULL.
+    ///
+    /// \param name A C string of which the segment memory address is to be
+    /// returned.  Must not be NULL.
+    /// \return The address associated with the name, or NULL if not found.
+    void* getNamedAddress(const char* name) {
+        // This public method implements common validation.  The actual
+        // work specific to the derived segment is delegated to the
+        // corresponding protected method.
+        if (!name) {
+            isc_throw(InvalidParameter,
+                      "NULL name is given to getNamedAddress");
+        }
+        return (getNamedAddressImpl(name));
+    }
+
+    /// \brief Delete a name previously associated with a segment address.
+    ///
+    /// This method deletes the association of the given \c name to
+    /// a corresponding segment address previously established by
+    /// \c setNamedAddress().  If there is no association for the given name
+    /// this method returns false; otherwise it returns true.
+    ///
+    /// See \c getNamedAddress() about exception consideration.
+    ///
+    /// \throw InvalidParameter name is NULL.
+    /// \throw MemorySegmentError Failure of implementation specific
+    /// validation.
+    ///
+    /// \param name A C string of which the segment memory address is to be
+    /// deleted. Must not be NULL.
+    bool clearNamedAddress(const char* name) {
+        // This public method implements common validation.  The actual
+        // work specific to the derived segment is delegated to the
+        // corresponding protected method.
+        if (!name) {
+            isc_throw(InvalidParameter,
+                      "NULL name is given to clearNamedAddress");
+        }
+        return (clearNamedAddressImpl(name));
+    }
+
+protected:
+    /// \brief Implementation of setNamedAddress beyond common validation.
+    virtual bool setNamedAddressImpl(const char* name, void* addr) = 0;
+
+    /// \brief Implementation of getNamedAddress beyond common validation.
+    virtual void* getNamedAddressImpl(const char* name) = 0;
+
+    /// \brief Implementation of clearNamedAddress beyond common validation.
+    virtual bool clearNamedAddressImpl(const char* name) = 0;
 };
 
 } // namespace util
 } // namespace isc
 
 #endif // MEMORY_SEGMENT_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/util/memory_segment_local.cc b/src/lib/util/memory_segment_local.cc
index 9c345c9..81548fd 100644
--- a/src/lib/util/memory_segment_local.cc
+++ b/src/lib/util/memory_segment_local.cc
@@ -48,7 +48,28 @@ MemorySegmentLocal::deallocate(void* ptr, size_t size) {
 
 bool
 MemorySegmentLocal::allMemoryDeallocated() const {
-    return (allocated_size_ == 0);
+    return (allocated_size_ == 0 && named_addrs_.empty());
+}
+
+void*
+MemorySegmentLocal::getNamedAddressImpl(const char* name) {
+    std::map<std::string, void*>::iterator found = named_addrs_.find(name);
+    if (found != named_addrs_.end()) {
+        return (found->second);
+    }
+    return (0);
+}
+
+bool
+MemorySegmentLocal::setNamedAddressImpl(const char* name, void* addr) {
+    named_addrs_[name] = addr;
+    return (false);
+}
+
+bool
+MemorySegmentLocal::clearNamedAddressImpl(const char* name) {
+    const size_t n_erased = named_addrs_.erase(name);
+    return (n_erased != 0);
 }
 
 } // namespace util
diff --git a/src/lib/util/memory_segment_local.h b/src/lib/util/memory_segment_local.h
index de35b87..1db55a0 100644
--- a/src/lib/util/memory_segment_local.h
+++ b/src/lib/util/memory_segment_local.h
@@ -17,6 +17,9 @@
 
 #include <util/memory_segment.h>
 
+#include <string>
+#include <map>
+
 namespace isc {
 namespace util {
 
@@ -63,14 +66,43 @@ public:
     /// deallocated, <code>false</code> otherwise.
     virtual bool allMemoryDeallocated() const;
 
+    /// \brief Local segment version of getNamedAddress.
+    ///
+    /// There's a small chance this method could throw std::bad_alloc.
+    /// It should be considered a fatal error.
+    virtual void* getNamedAddressImpl(const char* name);
+
+    /// \brief Local segment version of setNamedAddress.
+    ///
+    /// This version does not validate the given address to see whether it
+    /// belongs to this segment.
+    ///
+    /// This implementation of this method always returns \c false (but the
+    /// application should expect a return value of \c true unless it knows
+    /// the memory segment class is \c MemorySegmentLocal and needs to
+    /// exploit the fact).
+    virtual bool setNamedAddressImpl(const char* name, void* addr);
+
+    /// \brief Local segment version of clearNamedAddress.
+    ///
+    /// There's a small chance this method could throw std::bad_alloc.
+    /// It should be considered a fatal error.
+    virtual bool clearNamedAddressImpl(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
     // relation comparison, this is okay.
     size_t allocated_size_;
+
+    std::map<std::string, void*> named_addrs_;
 };
 
 } // namespace util
 } // namespace isc
 
 #endif // MEMORY_SEGMENT_LOCAL_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/util/memory_segment_mapped.cc b/src/lib/util/memory_segment_mapped.cc
new file mode 100644
index 0000000..e2ac944
--- /dev/null
+++ b/src/lib/util/memory_segment_mapped.cc
@@ -0,0 +1,382 @@
+// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <util/memory_segment_mapped.h>
+#include <util/unittests/check_valgrind.h>
+
+#include <exceptions/exceptions.h>
+
+#include <boost/scoped_ptr.hpp>
+#include <boost/interprocess/exceptions.hpp>
+#include <boost/interprocess/managed_mapped_file.hpp>
+#include <boost/interprocess/offset_ptr.hpp>
+#include <boost/interprocess/mapped_region.hpp>
+#include <boost/interprocess/sync/file_lock.hpp>
+
+#include <cassert>
+#include <string>
+#include <new>
+
+// boost::interprocess namespace is big and can cause unexpected import
+// (e.g., it has "read_only"), so it's safer to be specific for shortcuts.
+using boost::interprocess::basic_managed_mapped_file;
+using boost::interprocess::rbtree_best_fit;
+using boost::interprocess::null_mutex_family;
+using boost::interprocess::iset_index;
+using boost::interprocess::create_only_t;
+using boost::interprocess::create_only;
+using boost::interprocess::open_or_create_t;
+using boost::interprocess::open_or_create;
+using boost::interprocess::open_read_only;
+using boost::interprocess::open_only;
+using boost::interprocess::offset_ptr;
+
+namespace isc {
+namespace util {
+// Definition of class static constant so it can be referenced by address
+// or reference.
+const size_t MemorySegmentMapped::INITIAL_SIZE;
+
+// We customize managed_mapped_file to make it completely lock free.  In our
+// usage the application (or the system of applications) is expected to ensure
+// there's at most one writer process or concurrent writing the shared memory
+// segment is protected at a higher level.  Using the null mutex is mainly for
+// eliminating unnecessary dependency; the default version would require
+// (probably depending on the system) Pthread library that is actually not
+// needed and could cause various build time troubles.
+typedef basic_managed_mapped_file<char,
+                                  rbtree_best_fit<null_mutex_family>,
+                                  iset_index> BaseSegment;
+
+struct MemorySegmentMapped::Impl {
+    // Constructor for create-only (and read-write) mode.  this case is
+    // tricky because we want to remove any existing file but we also want
+    // to detect possible conflict with other readers or writers using
+    // file lock.
+    Impl(const std::string& filename, create_only_t, size_t initial_size) :
+        read_only_(false), filename_(filename)
+    {
+        try {
+            // First, try opening it in boost create_only mode; it fails if
+            // the file exists (among other reasons).
+            base_sgmt_.reset(new BaseSegment(create_only, filename.c_str(),
+                                             initial_size));
+        } catch (const boost::interprocess::interprocess_exception& ex) {
+            // We assume this is because the file exists; otherwise creating
+            // file_lock would fail with interprocess_exception, and that's
+            // what we want here (we wouldn't be able to create a segment
+            // anyway).
+            lock_.reset(new boost::interprocess::file_lock(filename.c_str()));
+
+            // Confirm there's no other reader or writer, and then release
+            // the lock before we remove the file; there's a chance of race
+            // here, but this check doesn't intend to guarantee 100% safety
+            // and so it should be okay.
+            checkWriter();
+            lock_.reset();
+
+            // now remove the file (if it happens to have been delete, this
+            // will be no-op), then re-open it with create_only.  this time
+            // it should succeed, and if it fails again, that's fatal for this
+            // constructor.
+            boost::interprocess::file_mapping::remove(filename.c_str());
+            base_sgmt_.reset(new BaseSegment(create_only, filename.c_str(),
+                                             initial_size));
+        }
+
+        // confirm there's no other user and there won't either.
+        lock_.reset(new boost::interprocess::file_lock(filename.c_str()));
+        checkWriter();
+    }
+
+    // Constructor for open-or-write (and read-write) mode
+    Impl(const std::string& filename, open_or_create_t, size_t initial_size) :
+        read_only_(false), filename_(filename),
+        base_sgmt_(new BaseSegment(open_or_create, filename.c_str(),
+                                   initial_size)),
+        lock_(new boost::interprocess::file_lock(filename.c_str()))
+    {
+        checkWriter();
+    }
+
+    // Constructor for existing segment, either read-only or read-write
+    Impl(const std::string& filename, bool read_only) :
+        read_only_(read_only), filename_(filename),
+        base_sgmt_(read_only_ ?
+                   new BaseSegment(open_read_only, filename.c_str()) :
+                   new BaseSegment(open_only, filename.c_str())),
+        lock_(new boost::interprocess::file_lock(filename.c_str()))
+    {
+        if (read_only_) {
+            checkReader();
+        } else {
+            checkWriter();
+        }
+    }
+
+    // Internal helper to grow the underlying mapped segment.
+    void growSegment() {
+        // We first need to unmap it before calling grow().
+        const size_t prev_size = base_sgmt_->get_size();
+        base_sgmt_.reset();
+
+        // Double the segment size.  In theory, this process could repeat
+        // so many times, counting to "infinity", and new_size eventually
+        // overflows.  That would cause a harsh disruption or unexpected
+        // behavior.  But we basically assume grow() would fail before this
+        // happens, so we assert it shouldn't happen.
+        const size_t new_size = prev_size * 2;
+        assert(new_size > prev_size);
+
+        if (!BaseSegment::grow(filename_.c_str(), new_size - prev_size)) {
+            throw std::bad_alloc();
+        }
+
+        try {
+            // Remap the grown file; this should succeed, but it's not 100%
+            // guaranteed.  If it fails we treat it as if we fail to create
+            // the new segment.
+            base_sgmt_.reset(new BaseSegment(open_only, filename_.c_str()));
+        } catch (const boost::interprocess::interprocess_exception& ex) {
+            throw std::bad_alloc();
+        }
+    }
+
+    // remember if the segment is opened read-only or not
+    const bool read_only_;
+
+    // mapped file; remember it in case we need to grow it.
+    const std::string filename_;
+
+    // actual Boost implementation of mapped segment.
+    boost::scoped_ptr<BaseSegment> base_sgmt_;
+
+private:
+    // helper methods and member to detect any reader-writer conflict at
+    // the time of construction using an advisory file lock.  The lock will
+    // be held throughout the lifetime of the object and will be released
+    // automatically.
+
+    void checkReader() {
+        if (!lock_->try_lock_sharable()) {
+            isc_throw(MemorySegmentOpenError,
+                      "mapped memory segment can't be opened as read-only "
+                      "with a writer process");
+        }
+    }
+
+    void checkWriter() {
+        if (!lock_->try_lock()) {
+            isc_throw(MemorySegmentOpenError,
+                      "mapped memory segment can't be opened as read-write "
+                      "with other reader or writer processes");
+        }
+    }
+
+    boost::scoped_ptr<boost::interprocess::file_lock> lock_;
+};
+
+MemorySegmentMapped::MemorySegmentMapped(const std::string& filename) :
+    impl_(NULL)
+{
+    try {
+        impl_ = new Impl(filename, true);
+    } catch (const boost::interprocess::interprocess_exception& ex) {
+        isc_throw(MemorySegmentOpenError,
+                  "failed to open mapped memory segment for " << filename
+                  << ": " << ex.what());
+    }
+}
+
+MemorySegmentMapped::MemorySegmentMapped(const std::string& filename,
+                                         OpenMode mode, size_t initial_size) :
+    impl_(NULL)
+{
+    try {
+        switch (mode) {
+        case OPEN_FOR_WRITE:
+            impl_ = new Impl(filename, false);
+            break;
+        case OPEN_OR_CREATE:
+            impl_ = new Impl(filename, open_or_create, initial_size);
+            break;
+        case CREATE_ONLY:
+            impl_ = new Impl(filename, create_only, initial_size);
+            break;
+        default:
+            isc_throw(InvalidParameter,
+                      "invalid open mode for MemorySegmentMapped: " << mode);
+        }
+    } catch (const boost::interprocess::interprocess_exception& ex) {
+        isc_throw(MemorySegmentOpenError,
+                  "failed to open mapped memory segment for " << filename
+                  << ": " << ex.what());
+    }
+}
+
+MemorySegmentMapped::~MemorySegmentMapped() {
+    if (impl_->base_sgmt_ && !impl_->read_only_) {
+        impl_->base_sgmt_->flush(); // note: this is exception free
+    }
+    delete impl_;
+}
+
+void*
+MemorySegmentMapped::allocate(size_t size) {
+    if (impl_->read_only_) {
+        isc_throw(MemorySegmentError, "allocate attempt on read-only segment");
+    }
+
+    // We explicitly check the free memory size; it appears
+    // managed_mapped_file::allocate() could incorrectly return a seemingly
+    // valid pointer for some very large requested size.
+    if (impl_->base_sgmt_->get_free_memory() >= size) {
+        void* ptr = impl_->base_sgmt_->allocate(size, std::nothrow);
+        if (ptr) {
+            return (ptr);
+        }
+    }
+
+    // Grow the mapped segment doubling the size until we have sufficient
+    // free memory in the revised segment for the requested size.
+    do {
+        impl_->growSegment();
+    } while (impl_->base_sgmt_->get_free_memory() < size);
+    isc_throw(MemorySegmentGrown, "mapped memory segment grown, size: "
+              << impl_->base_sgmt_->get_size() << ", free size: "
+              << impl_->base_sgmt_->get_free_memory());
+}
+
+void
+MemorySegmentMapped::deallocate(void* ptr, size_t) {
+    if (impl_->read_only_) {
+        isc_throw(MemorySegmentError,
+                  "deallocate attempt on read-only segment");
+    }
+
+    // the underlying deallocate() would deal with the case where ptr == NULL,
+    // but it's an undocumented behavior, so we handle it ourselves for safety.
+    if (!ptr) {
+        return;
+    }
+
+    impl_->base_sgmt_->deallocate(ptr);
+}
+
+bool
+MemorySegmentMapped::allMemoryDeallocated() const {
+    return (impl_->base_sgmt_->all_memory_deallocated());
+}
+
+void*
+MemorySegmentMapped::getNamedAddressImpl(const char* name) {
+    offset_ptr<void>* storage =
+        impl_->base_sgmt_->find<offset_ptr<void> >(name).first;
+    if (storage) {
+        return (storage->get());
+    }
+    return (NULL);
+}
+
+bool
+MemorySegmentMapped::setNamedAddressImpl(const char* name, void* addr) {
+    if (impl_->read_only_) {
+        isc_throw(MemorySegmentError, "setNamedAddress on read-only segment");
+    }
+
+    if (addr && !impl_->base_sgmt_->belongs_to_segment(addr)) {
+        isc_throw(MemorySegmentError, "address is out of segment: " << addr);
+    }
+
+    bool grown = false;
+    while (true) {
+        offset_ptr<void>* storage =
+            impl_->base_sgmt_->find_or_construct<offset_ptr<void> >(
+                name, std::nothrow)();
+        if (storage) {
+            *storage = addr;
+            return (grown);
+        }
+
+        impl_->growSegment();
+        grown = true;
+    }
+}
+
+bool
+MemorySegmentMapped::clearNamedAddressImpl(const char* name) {
+    if (impl_->read_only_) {
+        isc_throw(MemorySegmentError,
+                  "clearNamedAddress on read-only segment");
+    }
+
+    return (impl_->base_sgmt_->destroy<offset_ptr<void> >(name));
+}
+
+void
+MemorySegmentMapped::shrinkToFit() {
+    if (impl_->read_only_) {
+        isc_throw(MemorySegmentError, "shrinkToFit on read-only segment");
+    }
+
+    // It appears an assertion failure is triggered within Boost if the size
+    // is too small (happening if shrink_to_fit() is called twice without
+    // allocating any memory from the shrunk segment).  To work this around
+    // we'll make it no-op if the size is already reasonably small.
+    // Using INITIAL_SIZE is not 100% reliable as it's irrelevant to the
+    // internal constraint of the Boost implementation.  But, in practice,
+    // it should be sufficiently large and safe.
+    if (getSize() < INITIAL_SIZE) {
+        return;
+    }
+
+    // First, (unmap and) close the underlying file.
+    impl_->base_sgmt_.reset();
+
+    BaseSegment::shrink_to_fit(impl_->filename_.c_str());
+    try {
+        // Remap the shrunk file; this should succeed, but it's not 100%
+        // guaranteed.  If it fails we treat it as if we fail to create
+        // the new segment.
+        impl_->base_sgmt_.reset(
+            new BaseSegment(open_only, impl_->filename_.c_str()));
+    } catch (const boost::interprocess::interprocess_exception& ex) {
+        isc_throw(MemorySegmentError,
+                  "remap after shrink failed; segment is now unusable");
+    }
+}
+
+size_t
+MemorySegmentMapped::getSize() const {
+    return (impl_->base_sgmt_->get_size());
+}
+
+size_t
+MemorySegmentMapped::getCheckSum() const {
+    const size_t pagesize =
+        boost::interprocess::mapped_region::get_page_size();
+    const uint8_t* const cp_begin = static_cast<const uint8_t*>(
+        impl_->base_sgmt_->get_address());
+    const uint8_t* const cp_end = cp_begin + impl_->base_sgmt_->get_size();
+
+    size_t sum = 0;
+    for (const uint8_t* cp = cp_begin; cp < cp_end; cp += pagesize) {
+        sum += *cp;
+    }
+
+    return (sum);
+}
+
+} // namespace util
+} // namespace isc
diff --git a/src/lib/util/memory_segment_mapped.h b/src/lib/util/memory_segment_mapped.h
new file mode 100644
index 0000000..7685e30
--- /dev/null
+++ b/src/lib/util/memory_segment_mapped.h
@@ -0,0 +1,261 @@
+// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef MEMORY_SEGMENT_MAPPED_H
+#define MEMORY_SEGMENT_MAPPED_H
+
+#include <util/memory_segment.h>
+
+#include <boost/noncopyable.hpp>
+
+#include <string>
+
+namespace isc {
+namespace util {
+
+/// \brief Mapped-file based Memory Segment class.
+///
+/// This implementation of \c MemorySegment uses a concrete file to be mapped
+/// into memory.  Multiple processes can share the same mapped memory image.
+///
+/// This class provides two operation modes: read-only and read-write.
+/// A \c MemorySegmentMapped object in the read-only mode cannot modify the
+/// mapped memory image or other internal maintenance data of the object;
+/// In the read-write mode the object can allocate or deallocate memory
+/// from the mapped image, and the owner process can change the content.
+///
+/// Multiple processes can open multiple segments for the same file in
+/// read-only mode at the same time.  But there shouldn't be more than
+/// one process that opens segments for the same file in read-write mode
+/// at the same time.  Likewise, if one process opens a segment for a
+/// file in read-write mode, there shouldn't be any other process that
+/// opens a segment for the file in read-only mode. If one or more
+/// processes open segments for a file in read-only mode, there
+/// shouldn't be any other process that opens a segment for the file in
+/// read-write mode. This class tries to detect any violation of this
+/// restriction, but this does not intend to provide 100% safety.  It's
+/// generally the user's responsibility to ensure this condition.
+///
+/// The same restriction applies within the single process, whether
+/// multi-threaded or not: a process shouldn't open read-only and read-write
+/// (or multiple read-write) segments for the same file.  The violation
+/// detection mentioned above may or may not work in such cases due to
+/// limitation of the underlying API.  It's completely user's responsibility
+/// to prevent this from happening.  A single process may open multiple
+/// segments in read-only mode for the same file, but that shouldn't be
+/// necessary in practice; since it's read-only there wouldn't be a reason
+/// to have a redundant copy.
+class MemorySegmentMapped : boost::noncopyable, public MemorySegment {
+public:
+    /// \brief The default value of the mapped file size when newly created.
+    ///
+    /// Its value, 32KB, is an arbitrary choice, but considered to be
+    /// sufficiently but not too large.
+    static const size_t INITIAL_SIZE = 32768;
+
+    /// \brief Open modes of \c MemorySegmentMapped.
+    ///
+    /// These modes matter only for \c MemorySegmentMapped to be opened
+    /// in read-write mode, and specify further details of open operation.
+    enum OpenMode {
+        OPEN_FOR_WRITE = 0,     ///< Open only.  File must exist.
+        OPEN_OR_CREATE,         ///< If file doesn't exist it's created.
+        CREATE_ONLY ///< New file is created; existing one will be removed.
+    };
+
+    /// \brief Constructor in the read-only mode.
+    ///
+    /// This constructor will map the content of the given file into memory
+    /// in read-only mode; the resulting memory segment object cannot
+    /// be used with methods that would require the mapped memory (see method
+    /// descriptions).  Also, if the application tries to modify memory in
+    /// the segment, it will make the application crash.
+    ///
+    /// The file must have been created by the other version of the
+    /// constructor beforehand and must be readable for the process
+    /// constructing this object.  Otherwise \c MemorySegmentOpenError
+    /// exception will be thrown.
+    ///
+    /// \throw MemorySegmentOpenError The given file does not exist, is not
+    /// readable, or not valid mappable segment.  Or there is another process
+    /// that has already opened a segment for the file.
+    /// \throw std::bad_alloc (rare case) internal resource allocation
+    /// failure.
+    ///
+    /// \param filename The file name to be mapped to memory.
+    MemorySegmentMapped(const std::string& filename);
+
+    /// \brief Constructor in the read-write mode.
+    ///
+    /// This is similar to the read-only version of the constructor, but
+    /// does not have the restrictions that the read-only version has.
+    ///
+    /// The \c mode parameter specifies further details of how the segment
+    /// should be opened.
+    /// - OPEN_FOR_WRITE: this is open-only mode.  The file must exist,
+    ///   and it will be opened without any initial modification.
+    /// - OPEN_OR_CREATE: similar to OPEN_FOR_WRITE, but if the file does not
+    ///   exist, a new one will be created.  An existing file will be used
+    ///   any initial modification.
+    /// - CREATE_ONLY: a new file (of the given file name) will be created;
+    ///   any existing file of the same name will be removed.
+    ///
+    /// If OPEN_FOR_WRITE is specified, the specified file must exist
+    /// and be writable, and have been previously initialized by this
+    /// version of constructor either with OPEN_OR_CREATE or CREATE_ONLY.
+    /// If the mode is OPEN_OR_CREATE or CREATE_ONLY, and the file needs
+    /// to be created, then this method tries to create a new file of the
+    /// name and build internal data on it so that the file will be mappable
+    /// by this class object.  If any of these conditions is not met, or
+    /// create or initialization fails, \c MemorySegmentOpenError exception
+    /// will be thrown.
+    ///
+    /// This constructor also throws \c MemorySegmentOpenError when it
+    /// detects violation of the restriction on the mixed open of read-only
+    /// and read-write mode (see the class description).
+    ///
+    /// When initial_size is specified but is too small (including a value of
+    /// 0), the underlying Boost library will reject it, and this constructor
+    /// throws \c MemorySegmentOpenError exception.  The Boost documentation
+    /// does not specify how large it should be, but the default
+    /// \c INITIAL_SIZE should be sufficiently large in practice.
+    ///
+    /// \throw MemorySegmentOpenError see the description.
+    ///
+    /// \param filename The file name to be mapped to memory.
+    /// \param mode Open mode (see the description).
+    /// \param initial_size Specifies the size of the newly created file;
+    /// ignored if \c mode is OPEN_FOR_WRITE.
+    MemorySegmentMapped(const std::string& filename, OpenMode mode,
+                        size_t initial_size = INITIAL_SIZE);
+
+    /// \brief Destructor.
+    ///
+    /// If the object was constructed in the read-write mode and the underlying
+    /// memory segment wasn't broken due to an exceptional event, the
+    /// destructor ensures the content of the mapped memory is written back to
+    /// the corresponding file.
+    virtual ~MemorySegmentMapped();
+
+    /// \brief Allocate/acquire a segment of memory.
+    ///
+    /// This version can throw \c MemorySegmentGrown.
+    ///
+    /// This method cannot be called if the segment object is created in the
+    /// read-only mode; in that case MemorySegmentError will be thrown.
+    virtual void* allocate(size_t size);
+
+    /// \brief Deallocate/release a segment of memory.
+    ///
+    /// This implementation does not check the validity of \c size, because
+    /// if this segment object was constructed for an existing file to map,
+    /// the underlying segment may already contain allocated regions, so
+    /// this object cannot reliably detect whether it's safe to deallocate
+    /// the given size of memory from the underlying segment.
+    ///
+    /// Parameter \c ptr must point to an address that was returned by a
+    /// prior call to \c allocate() of this segment object, and there should
+    /// not be a \c MemorySegmentGrown exception thrown from \c allocate()
+    /// since then; if it was thrown the corresponding address must have been
+    /// adjusted some way; e.g., by re-fetching the latest mapped address
+    /// via \c getNamedAddress().
+    ///
+    /// This method cannot be called if the segment object is created in the
+    /// read-only mode; in that case MemorySegmentError will be thrown.
+    virtual void deallocate(void* ptr, size_t size);
+
+    virtual bool allMemoryDeallocated() const;
+
+    /// \brief Mapped segment version of setNamedAddress.
+    ///
+    /// This implementation detects if \c addr is invalid (see the base class
+    /// description) and throws \c MemorySegmentError in that case.
+    ///
+    /// This version of method should normally return false.  However,
+    /// it internally allocates memory in the segment for the name and
+    /// address to be stored, which can require segment extension, just like
+    /// allocate().  So it's possible to return true unlike
+    /// \c MemorySegmentLocal version of the method.
+    ///
+    /// This method cannot be called if the segment object is created in the
+    /// read-only mode; in that case MemorySegmentError will be thrown.
+    virtual bool setNamedAddressImpl(const char* name, void* addr);
+
+    /// \brief Mapped segment version of getNamedAddress.
+    ///
+    /// This version never throws.
+    virtual void* getNamedAddressImpl(const char* name);
+
+    /// \brief Mapped segment version of clearNamedAddress.
+    ///
+    /// This method cannot be called if the segment object is created in the
+    /// read-only mode; in that case MemorySegmentError will be thrown.
+    virtual bool clearNamedAddressImpl(const char* name);
+
+    /// \brief Shrink the underlying mapped segment to actually used size.
+    ///
+    /// When a large amount of memory is allocated and then deallocated
+    /// from the segment, this method can be used to keep the resulting
+    /// segment at a reasonable size.
+    ///
+    /// This method works by a best-effort basis, and does not guarantee
+    /// any specific result.
+    ///
+    /// This method is generally expected to be failure-free, but it's still
+    /// possible to fail.  For example, the underlying file may not be writable
+    /// at the time of shrink attempt; it also tries to remap the shrunk
+    /// segment internally, and there's a small chance it could fail.
+    /// In such a case it throws \c MemorySegmentError.  If it's thrown the
+    /// segment is not usable anymore.
+    ///
+    /// This method cannot be called if the segment object is created in the
+    /// read-only mode; in that case MemorySegmentError will be thrown.
+    ///
+    /// \throw MemorySegmentError see the description.
+    void shrinkToFit();
+
+    /// \brief Return the actual segment size.
+    ///
+    /// This is generally expected to be the file size to map.  It's
+    /// provided mainly for diagnosis and testing purposes; the application
+    /// shouldn't rely on specific return values of this method.
+    ///
+    /// \throw None
+    size_t getSize() const;
+
+    /// \brief Calculate a checksum over the memory segment.
+    ///
+    /// This method goes over all pages of the underlying mapped memory
+    /// segment, and returns the sum of the value of the first byte of each
+    /// page (wrapping around upon overflow).  It only proves weak integrity
+    /// of the file contents, but can run fast enough and will ensure all
+    /// pages are actually in memory.  The latter property will be useful
+    /// if the application cannot allow the initial page fault overhead.
+    ///
+    /// \throw None
+    size_t getCheckSum() const;
+
+private:
+    struct Impl;
+    Impl* impl_;
+};
+
+} // namespace util
+} // namespace isc
+
+#endif // MEMORY_SEGMENT_MAPPED_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/util/tests/Makefile.am b/src/lib/util/tests/Makefile.am
index 105322f..3ee16f9 100644
--- a/src/lib/util/tests/Makefile.am
+++ b/src/lib/util/tests/Makefile.am
@@ -34,6 +34,11 @@ run_unittests_SOURCES += lru_list_unittest.cc
 run_unittests_SOURCES += interprocess_sync_file_unittest.cc
 run_unittests_SOURCES += interprocess_sync_null_unittest.cc
 run_unittests_SOURCES += memory_segment_local_unittest.cc
+if USE_SHARED_MEMORY
+run_unittests_SOURCES += memory_segment_mapped_unittest.cc
+endif
+run_unittests_SOURCES += memory_segment_common_unittest.h
+run_unittests_SOURCES += memory_segment_common_unittest.cc
 run_unittests_SOURCES += qid_gen_unittest.cc
 run_unittests_SOURCES += random_number_generator_unittest.cc
 run_unittests_SOURCES += sha1_unittest.cc
@@ -41,6 +46,7 @@ run_unittests_SOURCES += socketsession_unittest.cc
 run_unittests_SOURCES += strutil_unittest.cc
 run_unittests_SOURCES += time_utilities_unittest.cc
 run_unittests_SOURCES += range_utilities_unittest.cc
+run_unittests_SOURCES += interprocess_util.h interprocess_util.cc
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
diff --git a/src/lib/util/tests/interprocess_sync_file_unittest.cc b/src/lib/util/tests/interprocess_sync_file_unittest.cc
index 6f23558..38d9026 100644
--- a/src/lib/util/tests/interprocess_sync_file_unittest.cc
+++ b/src/lib/util/tests/interprocess_sync_file_unittest.cc
@@ -12,48 +12,20 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include "util/interprocess_sync_file.h"
+#include <util/interprocess_sync_file.h>
 
 #include <util/unittests/check_valgrind.h>
+#include <util/tests/interprocess_util.h>
 #include <gtest/gtest.h>
 #include <unistd.h>
 
 using namespace std;
+using isc::util::test::parentReadState;
 
 namespace isc {
 namespace util {
 
 namespace {
-unsigned char
-parentReadLockedState (int fd) {
-  unsigned char locked = 0xff;
-
-  fd_set rfds;
-  FD_ZERO(&rfds);
-  FD_SET(fd, &rfds);
-
-  // We use select() here to wait for new data on the input end of
-  // the pipe. We wait for 5 seconds (an arbitrary value) for input
-  // data, and continue if no data is available. This is done so
-  // that read() is not blocked due to some issue in the child
-  // process (and the tests continue running).
-
-  struct timeval tv;
-  tv.tv_sec = 5;
-  tv.tv_usec = 0;
-
-  const int nfds = select(fd + 1, &rfds, NULL, NULL, &tv);
-  EXPECT_EQ(1, nfds);
-
-  if (nfds == 1) {
-      // Read status
-      ssize_t bytes_read = read(fd, &locked, sizeof(locked));
-      EXPECT_EQ(sizeof(locked), bytes_read);
-  }
-
-  return (locked);
-}
-
 TEST(InterprocessSyncFileTest, TestLock) {
     InterprocessSyncFile sync("test");
     InterprocessSyncLocker locker(sync);
@@ -99,7 +71,7 @@ TEST(InterprocessSyncFileTest, TestLock) {
             // Parent reads from pipe
             close(fds[1]);
 
-            const unsigned char locked = parentReadLockedState(fds[0]);
+            const unsigned char locked = parentReadState(fds[0]);
 
             close(fds[0]);
 
@@ -163,7 +135,7 @@ TEST(InterprocessSyncFileTest, TestMultipleFilesForked) {
             // Parent reads from pipe
             close(fds[1]);
 
-            const unsigned char locked = parentReadLockedState(fds[0]);
+            const unsigned char locked = parentReadState(fds[0]);
 
             close(fds[0]);
 
diff --git a/src/lib/util/tests/interprocess_util.cc b/src/lib/util/tests/interprocess_util.cc
new file mode 100644
index 0000000..dfb04b7
--- /dev/null
+++ b/src/lib/util/tests/interprocess_util.cc
@@ -0,0 +1,48 @@
+// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <gtest/gtest.h>
+
+#include <sys/select.h>
+#include <cstddef>
+
+namespace isc {
+namespace util {
+namespace test {
+
+unsigned char
+parentReadState(int fd) {
+  unsigned char result = 0xff;
+
+  fd_set rfds;
+  FD_ZERO(&rfds);
+  FD_SET(fd, &rfds);
+
+  struct timeval tv = {5, 0};
+
+  const int nfds = select(fd + 1, &rfds, NULL, NULL, &tv);
+  EXPECT_EQ(1, nfds);
+
+  if (nfds == 1) {
+      // Read status
+      const ssize_t bytes_read = read(fd, &result, sizeof(result));
+      EXPECT_EQ(sizeof(result), bytes_read);
+  }
+
+  return (result);
+}
+
+}
+}
+}
diff --git a/src/lib/util/tests/interprocess_util.h b/src/lib/util/tests/interprocess_util.h
new file mode 100644
index 0000000..286f9cf
--- /dev/null
+++ b/src/lib/util/tests/interprocess_util.h
@@ -0,0 +1,31 @@
+// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+namespace isc {
+namespace util {
+namespace test {
+/// \brief A helper utility for a simple synchronization with another process.
+///
+/// It waits for incoming data on a given file descriptor up to 5 seconds
+/// (arbitrary choice), read one byte data, and return it to the caller.
+/// On any failure it returns 0xff (255), so the sender process should use
+/// a different value to pass.
+unsigned char parentReadState(int fd);
+}
+}
+}
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/util/tests/memory_segment_common_unittest.cc b/src/lib/util/tests/memory_segment_common_unittest.cc
new file mode 100644
index 0000000..3810e0a
--- /dev/null
+++ b/src/lib/util/tests/memory_segment_common_unittest.cc
@@ -0,0 +1,92 @@
+// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <util/memory_segment.h>
+
+#include <exceptions/exceptions.h>
+
+#include <gtest/gtest.h>
+
+#include <cstring>
+#include <stdint.h>
+
+namespace isc {
+namespace util {
+namespace test {
+
+void
+checkSegmentNamedAddress(MemorySegment& segment, bool out_of_segment_ok) {
+    // NULL name is not allowed.
+    EXPECT_THROW(segment.getNamedAddress(NULL), InvalidParameter);
+
+    // If the name does not exist, NULL should be returned.
+    EXPECT_EQ(static_cast<void*>(NULL),
+              segment.getNamedAddress("test address"));
+
+    // Now set it
+    void* ptr32 = segment.allocate(sizeof(uint32_t));
+    const uint32_t test_val = 42;
+    *static_cast<uint32_t*>(ptr32) = test_val;
+    EXPECT_FALSE(segment.setNamedAddress("test address", ptr32));
+
+    // NULL name isn't allowed.
+    EXPECT_THROW(segment.setNamedAddress(NULL, ptr32), InvalidParameter);
+
+    // 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;
+    *static_cast<uint16_t*>(ptr16) = test_val16;
+    EXPECT_FALSE(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*>(NULL),
+              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.
+    EXPECT_FALSE(segment.setNamedAddress("null address", NULL));
+    EXPECT_EQ(static_cast<void*>(NULL),
+              segment.getNamedAddress("null address"));
+
+    // If the underlying implementation performs explicit check against
+    // out-of-segment address, confirm the behavior.
+    if (!out_of_segment_ok) {
+        uint8_t ch = 'A';
+        EXPECT_THROW(segment.setNamedAddress("local address", &ch),
+                     MemorySegmentError);
+    }
+
+    // clean them up all
+    segment.deallocate(ptr32, sizeof(uint32_t));
+    EXPECT_FALSE(segment.allMemoryDeallocated()); // not fully deallocated
+    segment.deallocate(ptr16, sizeof(uint16_t));  // not yet
+    EXPECT_FALSE(segment.allMemoryDeallocated());
+    EXPECT_TRUE(segment.clearNamedAddress("null address"));
+    // null name isn't allowed:
+    EXPECT_THROW(segment.clearNamedAddress(NULL), InvalidParameter);
+    EXPECT_TRUE(segment.allMemoryDeallocated()); // now everything is gone
+}
+
+}
+}
+}
diff --git a/src/lib/util/tests/memory_segment_common_unittest.h b/src/lib/util/tests/memory_segment_common_unittest.h
new file mode 100644
index 0000000..ebc612b
--- /dev/null
+++ b/src/lib/util/tests/memory_segment_common_unittest.h
@@ -0,0 +1,36 @@
+// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <util/memory_segment.h>
+
+namespace isc {
+namespace util {
+namespace test {
+
+/// \brief Implementation dependent checks on memory segment named addresses.
+///
+/// This function contains a set of test cases for given memory segment
+/// regarding "named address" methods.  The test cases basically only depend
+/// on the base class interfaces, but if the underlying implementation does
+/// not check if the given address to setNamedAddress() belongs to the segment,
+/// out_of_segment_ok should be set to true.
+void checkSegmentNamedAddress(MemorySegment& segment, bool out_of_segment_ok);
+
+}
+}
+}
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/util/tests/memory_segment_local_unittest.cc b/src/lib/util/tests/memory_segment_local_unittest.cc
index 64b7292..5176c88 100644
--- a/src/lib/util/tests/memory_segment_local_unittest.cc
+++ b/src/lib/util/tests/memory_segment_local_unittest.cc
@@ -12,7 +12,9 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include "util/memory_segment_local.h"
+#include <util/tests/memory_segment_common_unittest.h>
+
+#include <util/memory_segment_local.h>
 #include <exceptions/exceptions.h>
 #include <gtest/gtest.h>
 #include <memory>
@@ -106,4 +108,9 @@ TEST(MemorySegmentLocal, TestNullDeallocate) {
     EXPECT_TRUE(segment->allMemoryDeallocated());
 }
 
+TEST(MemorySegmentLocal, namedAddress) {
+    MemorySegmentLocal segment;
+    isc::util::test::checkSegmentNamedAddress(segment, true);
+}
+
 } // anonymous namespace
diff --git a/src/lib/util/tests/memory_segment_mapped_unittest.cc b/src/lib/util/tests/memory_segment_mapped_unittest.cc
new file mode 100644
index 0000000..1d9979d
--- /dev/null
+++ b/src/lib/util/tests/memory_segment_mapped_unittest.cc
@@ -0,0 +1,620 @@
+// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#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 {
+// Shortcut to keep code shorter
+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; // intentionally hardcoded
+
+// A simple RAII-style wrapper for a pipe.  Several tests in this file use
+// pipes, so this helper will be useful.
+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);
+    }
+
+    // For initialization and for tests after the segment possibly becomes
+    // broken.
+    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(MemorySegmentMappedConstantTest, staticVariables) {
+    // Attempt to take address of MemorySegmentMapped::INITIAL_SIZE.
+    // It helps in case we accidentally remove the definition from the main
+    // code.
+    EXPECT_EQ(DEFAULT_INITIAL_SIZE, *(&MemorySegmentMapped::INITIAL_SIZE));
+}
+
+TEST_F(MemorySegmentMappedTest, createAndModify) {
+    // We are going to do the same set of basic tests twice; one after creating
+    // the mapped file, the other by re-opening the existing file in the
+    // read-write mode.
+    for (int i = 0; i < 2; ++i) {
+        // It should have the default size (intentionally hardcoded)
+        EXPECT_EQ(DEFAULT_INITIAL_SIZE, segment_->getSize());
+
+        // By default, nothing is allocated.
+        EXPECT_TRUE(segment_->allMemoryDeallocated());
+
+        void* ptr = segment_->allocate(1024);
+        EXPECT_NE(static_cast<void*>(NULL), ptr);
+
+        // Now, we have an allocation:
+        EXPECT_FALSE(segment_->allMemoryDeallocated());
+
+        // deallocate it; it shouldn't cause disruption.
+        segment_->deallocate(ptr, 1024);
+
+        EXPECT_TRUE(segment_->allMemoryDeallocated());
+
+        // re-open it in read-write mode, but don't try to create it
+        // this time.
+        segment_.reset();       // make sure close is first.
+        segment_.reset(new MemorySegmentMapped(mapped_file, OPEN_FOR_WRITE));
+    }
+}
+
+TEST_F(MemorySegmentMappedTest, createWithSize) {
+    boost::interprocess::file_mapping::remove(mapped_file);
+
+    // Re-create the mapped file with a non-default initial size, and confirm
+    // the size is actually the specified one.
+    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) {
+    // First, allocate some data in the existing segment
+    EXPECT_TRUE(segment_->allocate(16));
+    // Close it, and then open it again in the create-only mode.  the existing
+    // file should be internally removed, and so the resulting segment
+    // should be "empty" (all deallocated).
+    segment_.reset();
+    segment_.reset(new MemorySegmentMapped(mapped_file, CREATE_ONLY));
+    EXPECT_TRUE(segment_->allMemoryDeallocated());
+}
+
+TEST_F(MemorySegmentMappedTest, openFail) {
+    // The given file is directory
+    EXPECT_THROW(MemorySegmentMapped("/", OPEN_OR_CREATE),
+                 MemorySegmentOpenError);
+
+    // file doesn't exist and directory isn't writable (we assume the
+    // following path is not writable for the user running the test).
+    EXPECT_THROW(MemorySegmentMapped("/random-glkwjer098/test.mapped",
+                                     OPEN_OR_CREATE), MemorySegmentOpenError);
+
+    // It should fail when file doesn't exist and it's read-only (so
+    // open-only).
+    EXPECT_THROW(MemorySegmentMapped(TEST_DATA_BUILDDIR "/nosuchfile.mapped"),
+                 MemorySegmentOpenError);
+    // Likewise, it should fail in read-write mode when creation is
+    // suppressed.
+    EXPECT_THROW(MemorySegmentMapped(TEST_DATA_BUILDDIR "/nosuchfile.mapped",
+                                     OPEN_FOR_WRITE), MemorySegmentOpenError);
+
+    // creating with a very small size fails (for sure about 0, and other
+    // small values should also make it fail, but it's internal restriction
+    // of Boost and cannot be predictable).
+    EXPECT_THROW(MemorySegmentMapped(mapped_file, OPEN_OR_CREATE, 0),
+                 MemorySegmentOpenError);
+
+    // invalid read-write mode
+    EXPECT_THROW(MemorySegmentMapped(
+                     mapped_file,
+                     static_cast<MemorySegmentMapped::OpenMode>(
+                         static_cast<int>(CREATE_ONLY) + 1)),
+                 isc::InvalidParameter);
+
+    // Close the existing segment, break its file with bogus data, and
+    // try to reopen.  It should fail with exception whether in the
+    // read-only or read-write, or "create if not exist" mode.
+    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) {
+    // Various case of allocation.  The simplest cases are covered above.
+
+    // Initially, nothing is allocated.
+    EXPECT_TRUE(segment_->allMemoryDeallocated());
+
+    // (Clearly) exceeding the available size, which should cause growing
+    // the segment
+    const size_t prev_size = segment_->getSize();
+    EXPECT_THROW(segment_->allocate(prev_size + 1), MemorySegmentGrown);
+    // The size should have been doubled.
+    EXPECT_EQ(prev_size * 2, segment_->getSize());
+    // But nothing should have been allocated.
+    EXPECT_TRUE(segment_->allMemoryDeallocated());
+
+    // Now, the allocation should now succeed.
+    void* ptr = segment_->allocate(prev_size + 1);
+    EXPECT_NE(static_cast<void*>(NULL), ptr);
+    EXPECT_FALSE(segment_->allMemoryDeallocated());
+
+    // Same set of checks, but for a larger size.
+    EXPECT_THROW(segment_->allocate(prev_size * 10), MemorySegmentGrown);
+    // the segment should have grown to the minimum power-of-2 size that
+    // could allocate the given size of memory.
+    EXPECT_EQ(prev_size * 16, segment_->getSize());
+    // And allocate() should now succeed.
+    ptr = segment_->allocate(prev_size * 10);
+    EXPECT_NE(static_cast<void*>(NULL), ptr);
+
+    // (we'll left the regions created in the file there; the entire file
+    // will be removed at the end of the test)
+}
+
+TEST_F(MemorySegmentMappedTest, badAllocate) {
+    // Make the mapped file non-writable; managed_mapped_file::grow() will
+    // fail, resulting in std::bad_alloc
+    const int ret = chmod(mapped_file, 0444);
+    ASSERT_EQ(0, ret);
+
+    EXPECT_THROW(segment_->allocate(DEFAULT_INITIAL_SIZE * 2), std::bad_alloc);
+}
+
+// XXX: this test can cause too strong side effect (creating a very large
+// file), so we disable it by default
+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); // this is okay
+    // This is duplicate dealloc; should trigger assertion failure.
+    if (!isc::util::unittests::runningOnValgrind()) {
+        EXPECT_DEATH_IF_SUPPORTED({segment_->deallocate(ptr, 4);}, "");
+        resetSegment();   // the segment is possibly broken; reset it.
+    }
+
+    // Deallocating at an invalid address; this would result in crash (the
+    // behavior may not be portable enough; if so we should disable it by
+    // default).
+    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();
+    }
+
+    // Invalid size; this implementation doesn't detect such errors.
+    ptr = segment_->allocate(4);
+    EXPECT_NE(static_cast<void*>(NULL), ptr);
+    segment_->deallocate(ptr, 8);
+    EXPECT_TRUE(segment_->allMemoryDeallocated());
+}
+
+// A helper of namedAddress.
+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) {
+    // common test cases
+    isc::util::test::checkSegmentNamedAddress(*segment_, false);
+
+    // Set it again and read it in the read-only mode.
+    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();           // close it before opening another one
+
+    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")));
+
+    // try to set an unusually long name.  We re-create the file so
+    // creating the name would cause allocation failure and trigger internal
+    // segment extension.
+    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'); // definitely larger than segment
+    // setNamedAddress should return true, indicating segment has grown.
+    EXPECT_TRUE(segment_->setNamedAddress(long_name.c_str(), NULL));
+    EXPECT_EQ(static_cast<void*>(NULL),
+              segment_->getNamedAddress(long_name.c_str()));
+
+    // Check contents pointed by named addresses survive growing and
+    // shrinking segment.
+    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); // arbitrarily chosen small data
+    data_list["data2"] =
+        std::vector<uint8_t>(5000); // larger than usual segment size
+    data_list["data3"] =
+        std::vector<uint8_t>(65535); // bigger than most usual data
+    bool grown = false;
+
+    // Allocate memory and store data
+    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;
+            }
+        }
+    }
+    // Confirm there's at least one segment extension
+    EXPECT_TRUE(grown);
+    // Check named data are still valid
+    for (TestData::iterator it = data_list.begin(); it != data_list.end();
+         ++it)
+    {
+        checkNamedData(it->first, it->second, *segment_);
+    }
+
+    // Confirm they are still valid, while we shrink the segment.  We'll
+    // intentionally delete bigger data first so it'll be more likely that
+    // shrink has some real effect.
+    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) {
+    // Test using fork() doesn't work well on valgrind
+    if (isc::util::unittests::runningOnValgrind()) {
+        return;
+    }
+
+    // allocate some data and name its address
+    void* ptr = segment_->allocate(sizeof(uint32_t));
+    *static_cast<uint32_t*>(ptr) = 424242;
+    segment_->setNamedAddress("test address", ptr);
+
+    // close the read-write segment at this point.  our intended use case is
+    // to have one or more reader process or at most one exclusive writer
+    // process.  so we don't mix reader and writer.
+    segment_.reset();
+
+    // Spawn another process and have it open and read the same data.
+    PipeHolder pipe_to_child;
+    PipeHolder pipe_to_parent;
+    const pid_t child_pid = fork();
+    ASSERT_NE(-1, child_pid);
+    if (child_pid == 0) {
+        // child: wait until the parent has opened the read-only segment.
+        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);
+            // tell the parent whether it succeeded. 0 means it did,
+            // 0xff means it failed.
+            const char ok = (val == 424242) ? 0 : 0xff;
+            EXPECT_EQ(1, write(pipe_to_parent.getWriteFD(), &ok, sizeof(ok)));
+        }
+        exit(0);
+    }
+    // parent: open another read-only segment, then tell the child to open
+    // its own segment.
+    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)));
+
+    // wait for the completion of the child and checks the result.
+    EXPECT_EQ(0, parentReadState(pipe_to_parent.getReadFD()));
+}
+
+TEST_F(MemorySegmentMappedTest, nullDeallocate) {
+    // NULL deallocation is a no-op.
+    EXPECT_NO_THROW(segment_->deallocate(0, 1024));
+    EXPECT_TRUE(segment_->allMemoryDeallocated());
+}
+
+TEST_F(MemorySegmentMappedTest, shrink) {
+    segment_->shrinkToFit();
+    // Normally we should be able to expect that the resulting size is
+    // smaller than the initial default size. But it's not really
+    // guaranteed by the API, so we may have to disable this check (or
+    // use EXPECT_GE).
+    const size_t shrinked_size = segment_->getSize();
+    EXPECT_GT(DEFAULT_INITIAL_SIZE, shrinked_size);
+
+    // Another shrink shouldn't cause disruption.  We expect the size is
+    // the same so we confirm it.  The underlying library doesn't guarantee
+    // that, so we may have to change it to EXPECT_GE if the test fails
+    // on that (MemorySegmentMapped class doesn't rely on this expectation,
+    // so it's okay even if it does not always hold).
+    segment_->shrinkToFit();
+    EXPECT_EQ(shrinked_size, segment_->getSize());
+
+    // Check that the segment is still usable after shrink.
+    void* p = segment_->allocate(sizeof(uint32_t));
+    segment_->deallocate(p, sizeof(uint32_t));
+}
+
+TEST_F(MemorySegmentMappedTest, violateReadOnly) {
+    // Create a named address for the tests below, then reset the writer
+    // segment so that it won't fail for different reason (i.e., read-write
+    // conflict).
+    void* ptr = segment_->allocate(sizeof(uint32_t));
+    segment_->setNamedAddress("test address", ptr);
+    segment_.reset();
+
+    // Attempts to modify memory from the read-only segment directly
+    // will result in a crash.
+    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;
+            }, "");
+    }
+
+    // If the segment is opened in the read-only mode, modification
+    // attempts are prohibited. When detectable it must result in an
+    // exception.
+    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);
+    // allocation that would otherwise require growing the segment; permission
+    // check should be performed before that.
+    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();
+
+    // We assume the initial segment size is sufficiently larger than
+    // the page size.  We'll allocate memory of the page size, and
+    // increment all bytes in that page by one.  It will increase our
+    // simple checksum value (which just uses the first byte of each
+    // page) by one, too.
+    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());
+}
+
+// Mode of opening segments in the tests below.
+enum TestOpenMode {
+    READER = 0,
+    WRITER_FOR_WRITE,
+    WRITER_OPEN_OR_CREATE,
+    WRITER_CREATE_ONLY
+};
+
+// A shortcut to attempt to open a specified type of segment (generally
+// expecting it to fail)
+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;
+    }
+}
+
+// Common logic for conflictReaderWriter test.  The segment opened in the
+// parent process will prevent the segment in the child from being used.
+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;                 // 0 = open success, 1 = fail
+        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);
+    }
+
+    // parent: open a segment, then tell the child to open its own segment of
+    // the specified type.
+    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)));
+
+    // wait for the completion of the child and checks the result.  open at
+    // the child side should fail, so the parent should get the value of 1.
+    EXPECT_EQ(1, parentReadState(pipe_to_parent.getReadFD()));
+}
+
+TEST_F(MemorySegmentMappedTest, conflictReaderWriter) {
+    // Test using fork() doesn't work well on valgrind
+    if (isc::util::unittests::runningOnValgrind()) {
+        return;
+    }
+
+    // Below, we check all combinations of conflicts between reader and writer
+    // will fail.  We first make sure there's no other reader or writer.
+    segment_.reset();
+
+    // reader opens segment, then writer (OPEN_FOR_WRITE) tries to open
+    conflictCheck(READER, WRITER_FOR_WRITE);
+    // reader opens segment, then writer (OPEN_OR_CREATE) tries to open
+    conflictCheck(READER, WRITER_OPEN_OR_CREATE);
+    // reader opens segment, then writer (CREATE_ONLY) tries to open
+    conflictCheck(READER, WRITER_CREATE_ONLY);
+
+    // writer (OPEN_FOR_WRITE) opens a segment, then reader tries to open
+    conflictCheck(WRITER_FOR_WRITE, READER);
+    // writer (OPEN_OR_CREATE) opens a segment, then reader tries to open
+    conflictCheck(WRITER_OPEN_OR_CREATE, READER);
+    // writer (CREATE_ONLY) opens a segment, then reader tries to open
+    conflictCheck(WRITER_CREATE_ONLY, READER);
+
+    // writer opens segment, then another writer (OPEN_FOR_WRITE) tries to open
+    conflictCheck(WRITER_FOR_WRITE, WRITER_FOR_WRITE);
+    // writer opens segment, then another writer (OPEN_OR_CREATE) tries to open
+    conflictCheck(WRITER_FOR_WRITE, WRITER_OPEN_OR_CREATE);
+    // writer opens segment, then another writer (CREATE_ONLY) tries to open
+    conflictCheck(WRITER_FOR_WRITE, WRITER_CREATE_ONLY);
+}
+
+}



More information about the bind10-changes mailing list