Browse Source

[trac3614] removed no longer used --with-shared-memory and dependencies

Francis Dupont 10 years ago
parent
commit
adee8c93f7

+ 5 - 0
ChangeLog

@@ -1,3 +1,8 @@
+847.	[build]		fdupont
+	Removed unused configuration option --with-shared-memory
+	and associated files and variables.
+	(Trac #3614, git ...)
+
 846.	[bug]		fdupont
 	Fixed subdir-objects warnings from recent versions of autotools,
 	e.g., on Apple OSX.

+ 0 - 25
configure.ac

@@ -1041,31 +1041,6 @@ 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" -a "$want_dns" = "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 by rerunning this script with --without-shared-memory; 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])
-if test "x$use_shared_memory" = "xyes"; then
-    AC_DEFINE(USE_SHARED_MEMORY, 1, [Define to 1 if shared memory support is enabled])
-fi
-AC_SUBST(BOOST_MAPPED_FILE_CXXFLAG)
-
-if test "$BOOST_OFFSET_PTR_OLD" = "yes" -a "$use_shared_memory" = "yes" -a "$want_dns" = "yes"; then
-    AC_MSG_ERROR([You're trying to compile against boost older than 1.48 with
-shared memory. Older versions of boost have a bug which causes segfaults in
-offset_ptr implementation when compiled by GCC with optimisations enabled.
-See ticket no. 3025 for details.
-
-Either update boost to newer version or use --without-shared-memory.
-Note that most users likely don't need shared memory support.
-])
-fi
-
 # Add some default CPP flags needed for Boost, identified by the AX macro.
 CPPFLAGS="$CPPFLAGS $CPPFLAGS_BOOST_THREADCONF"
 

+ 0 - 58
m4macros/ax_boost_for_kea.m4

@@ -23,20 +23,9 @@ 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   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.
 dnl   BOOST_STATIC_ASSERT_WOULDFAIL set to "yes" if BOOST_STATIC_ASSERT would
 dnl                                 cause build error; otherwise set to "no"
 
-dnl   BOOST_OFFSET_PTR_OLD set to "yes" if the version of boost is older than
-dnl                        1.48. Older versions of boost have a bug which
-dnl                        causes segfaults in offset_ptr implementation when
-dnl                        compiled by GCC with optimisations enabled.
-dnl                        See ticket no. 3025 for details.
-
 AC_DEFUN([AX_BOOST_FOR_KEA], [
 AC_LANG_SAVE
 AC_LANG([C++])
@@ -119,56 +108,9 @@ if test "X$GXX" = "Xyes"; then
     BOOST_NUMERIC_CAST_WOULDFAIL=yes])
 
    CXXFLAGS="$CXXFLAGS_SAVED"
-
-   AC_MSG_CHECKING([Boost rbtree is old])
-   AC_TRY_COMPILE([
-   #include <boost/version.hpp>
-   #if BOOST_VERSION < 104800
-   #error Too old
-   #endif
-   ],,[AC_MSG_RESULT(no)
-       BOOST_OFFSET_PTR_OLD=no
-   ],[AC_MSG_RESULT(yes)
-      BOOST_OFFSET_PTR_OLD=yes])
 else
    # This doesn't matter for non-g++
    BOOST_NUMERIC_CAST_WOULDFAIL=no
-   BOOST_OFFSET_PTR_OLD=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 $CLANG_CXXFLAGS -Wall -Wextra -Werror"
-  try_flags="$try_flags -Wno-error"
-fi
-
-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 $CLANG_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
 
 # BOOST_STATIC_ASSERT in versions below Boost 1.54.0 is known to result

+ 0 - 15
src/lib/util/Makefile.am

@@ -7,18 +7,6 @@ AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/exceptions -I$(top_builddir)/src/lib/exceptions
 AM_CPPFLAGS += $(BOOST_INCLUDES)
 AM_CXXFLAGS = $(KEA_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 = libkea-util.la
 libkea_util_la_SOURCES  = csv_file.h csv_file.cc
@@ -29,9 +17,6 @@ libkea_util_la_SOURCES += buffer.h io_utilities.h
 libkea_util_la_SOURCES += time_utilities.h time_utilities.cc
 libkea_util_la_SOURCES += memory_segment.h
 libkea_util_la_SOURCES += memory_segment_local.h memory_segment_local.cc
-if USE_SHARED_MEMORY
-libkea_util_la_SOURCES += memory_segment_mapped.h memory_segment_mapped.cc
-endif
 libkea_util_la_SOURCES += optional_value.h
 libkea_util_la_SOURCES += range_utilities.h
 libkea_util_la_SOURCES += signal_set.cc signal_set.h

+ 0 - 466
src/lib/util/memory_segment_mapped.cc

@@ -1,466 +0,0 @@
-// 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>
-
-#include <stdint.h>
-
-// 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 {
-
-namespace { // unnamed namespace
-
-const char* const RESERVED_NAMED_ADDRESS_STORAGE_NAME =
-    "_RESERVED_NAMED_ADDRESS_STORAGE";
-
-} // end of unnamed namespace
-
-
-// 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();
-        reserveMemory();
-    }
-
-    // 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();
-        reserveMemory();
-    }
-
-    // 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();
-        }
-        reserveMemory();
-    }
-
-    void reserveMemory(bool no_grow = false) {
-        if (!read_only_) {
-            // Reserve a named address for use during
-            // setNamedAddress(). Though this will almost always succeed
-            // on the first try during construction, it may require
-            // multiple attempts later during a call from
-            // allMemoryDeallocated() when the segment has been in use
-            // for a while.
-            while (true) {
-                const offset_ptr<void>* reserved_storage =
-                    base_sgmt_->find_or_construct<offset_ptr<void> >(
-                        RESERVED_NAMED_ADDRESS_STORAGE_NAME, std::nothrow)();
-
-                if (reserved_storage) {
-                    break;
-                }
-                assert(!no_grow);
-
-                growSegment();
-            }
-        }
-    }
-
-    void freeReservedMemory() {
-        if (!read_only_) {
-            const bool deleted = base_sgmt_->destroy<offset_ptr<void> >
-                (RESERVED_NAMED_ADDRESS_STORAGE_NAME);
-            assert(deleted);
-        }
-    }
-
-    // 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_->flush();
-        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);
-
-        const bool grown = BaseSegment::grow(filename_.c_str(),
-                                             new_size - prev_size);
-
-        // Remap the file, whether or not grow() succeeded.  this should
-        // normally succeed(*), but it's not 100% guaranteed.  We abort
-        // if it fails (see the method description in the header file).
-        // (*) Although it's not formally documented, the implementation
-        // of grow() seems to provide strong guarantee, i.e, if it fails
-        // the underlying file can be used with the previous size.
-        try {
-            base_sgmt_.reset(new BaseSegment(open_only, filename_.c_str()));
-        } catch (...) {
-            abort();
-        }
-        if (!grown) {
-            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_->freeReservedMemory();
-        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 {
-    // This method is not technically const, but it reserves the
-    // const-ness property. In case of exceptions, we abort here. (See
-    // ticket #2850 for additional commentary.)
-    try {
-        impl_->freeReservedMemory();
-        const bool result = impl_->base_sgmt_->all_memory_deallocated();
-        // reserveMemory() should succeed now as the memory was already
-        // allocated, so we set no_grow to true.
-        impl_->reserveMemory(true);
-        return (result);
-    } catch (...) {
-        abort();
-    }
-}
-
-MemorySegment::NamedAddressResult
-MemorySegmentMapped::getNamedAddressImpl(const char* name) const {
-    offset_ptr<void>* storage =
-        impl_->base_sgmt_->find<offset_ptr<void> >(name).first;
-    if (storage) {
-        return (NamedAddressResult(true, storage->get()));
-    }
-    return (NamedAddressResult(false, 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);
-    }
-
-    // Temporarily save the passed addr into pre-allocated offset_ptr in
-    // case there are any relocations caused by allocations.
-    offset_ptr<void>* reserved_storage =
-        impl_->base_sgmt_->find<offset_ptr<void> >(
-            RESERVED_NAMED_ADDRESS_STORAGE_NAME).first;
-    assert(reserved_storage);
-    *reserved_storage = addr;
-
-    bool grown = false;
-    while (true) {
-        offset_ptr<void>* storage =
-            impl_->base_sgmt_->find_or_construct<offset_ptr<void> >(
-                name, std::nothrow)();
-        if (storage) {
-            // Move the address from saved offset_ptr into the
-            // newly-allocated storage.
-            reserved_storage =
-                impl_->base_sgmt_->find<offset_ptr<void> >(
-                    RESERVED_NAMED_ADDRESS_STORAGE_NAME).first;
-            assert(reserved_storage);
-            *storage = *reserved_storage;
-            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 the underlying file.
-    impl_->base_sgmt_->flush();
-    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.  Note that this is different from the case where
-        // reset() after grow() fails.  While the same argument can apply
-        // in theory, it should be less likely that other methods will be
-        // called after shrinkToFit() (and the destructor can still be called
-        // safely), so we give the application an opportunity to handle the
-        // case as gracefully as possible.
-        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

+ 0 - 268
src/lib/util/memory_segment_mapped.h

@@ -1,268 +0,0 @@
-// 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.  Furthermore, there is
-    /// a very small chance that the object loses its integrity and can't be
-    /// usable in the case where \c MemorySegmentGrown would be thrown.
-    /// In this case, throwing a different exception wouldn't help, because
-    /// an application trying to provide exception safety might then call
-    /// deallocate() or named address APIs on this object, which would simply
-    /// cause a crash.  So, while suboptimal, this method just aborts the
-    /// program in this case, indicating there's no hope to shutdown cleanly.
-    ///
-    /// 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 NamedAddressResult getNamedAddressImpl(const char* name) const;
-
-    /// \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:

+ 0 - 3
src/lib/util/tests/Makefile.am

@@ -35,9 +35,6 @@ run_unittests_SOURCES += hex_unittest.cc
 run_unittests_SOURCES += io_utilities_unittest.cc
 run_unittests_SOURCES += lru_list_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 += optional_value_unittest.cc

+ 0 - 650
src/lib/util/tests/memory_segment_mapped_unittest.cc

@@ -1,650 +0,0 @@
-// 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/unittests/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::unittests::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) {
-    // If the test is run as the root user, the following allocate()
-    // call will result in a successful MemorySegmentGrown exception,
-    // instead of an abort (due to insufficient permissions during
-    // reopen).
-    if (getuid() == 0) {
-        std::cerr << "Skipping test as it's run as the root user" << std::endl;
-        return;
-    }
-
-    // Make the mapped file non-writable; managed_mapped_file::grow() will
-    // fail, resulting in abort.
-    const int ret = chmod(mapped_file, 0444);
-    ASSERT_EQ(0, ret);
-
-    if (!isc::util::unittests::runningOnValgrind()) {
-        EXPECT_DEATH_IF_SUPPORTED(
-            {segment_->allocate(DEFAULT_INITIAL_SIZE * 2);}, "");
-    }
-}
-
-// 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)
-{
-    const MemorySegment::NamedAddressResult result =
-        sgmt.getNamedAddress(name.c_str());
-    ASSERT_TRUE(result.first);
-    ASSERT_TRUE(result.second);
-    EXPECT_EQ(0, std::memcmp(result.second, &data[0], data.size()));
-
-    if (delete_after_check) {
-        sgmt.deallocate(result.second, 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));
-    MemorySegment::NamedAddressResult result =
-        segment_->getNamedAddress("test address");
-    ASSERT_TRUE(result.first);
-    EXPECT_EQ(test_val16, *static_cast<const uint16_t*>(result.second));
-
-    // 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));
-    result = segment_->getNamedAddress(long_name.c_str());
-    EXPECT_TRUE(result.first);
-    EXPECT_FALSE(result.second);
-
-    // 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);
-        const MemorySegment::NamedAddressResult result =
-            sgmt.getNamedAddress("test address");
-        ASSERT_TRUE(result.first);
-        EXPECT_TRUE(result.second);
-        if (result.second) {
-            const uint32_t val = *static_cast<const uint32_t*>(result.second);
-            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));
-    const MemorySegment::NamedAddressResult result =
-        segment_->getNamedAddress("test address");
-    ASSERT_TRUE(result.first);
-    ASSERT_TRUE(result.second);
-    EXPECT_EQ(424242, *static_cast<const uint32_t*>(result.second));
-    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 = NULL;
-    while (!p) {
-        try {
-            p = segment_->allocate(sizeof(uint32_t));
-        } catch (const MemorySegmentGrown&) {
-            // Do nothing. Just try again.
-        }
-    }
-    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);
-                const MemorySegment::NamedAddressResult result =
-                    segment_ro.getNamedAddress("test address");
-                ASSERT_TRUE(result.first);
-                ASSERT_TRUE(result.second);
-                *static_cast<uint32_t*>(result.second) = 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);
-    const MemorySegment::NamedAddressResult result =
-        segment_ro.getNamedAddress("test address");
-    ASSERT_TRUE(result.first);
-    EXPECT_NE(static_cast<void*>(NULL), result.second);
-
-    EXPECT_THROW(segment_ro.deallocate(result.second, 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);
-}
-
-}